class Color32 {
    constructor(r, g, b, a = 255) {
        this.values = new Uint8ClampedArray(4);
        this.values[0] = r;
        this.values[1] = g;
        this.values[2] = b;
        this.values[3] = a;
    }
    get R() {
        return this.values[0];
    }
    get G() {
        return this.values[1];
    }
    get B() {
        return this.values[2];
    }
    get A() {
        return this.values[3];
    }
    set R(v) {
        this.values[0] = v;
    }
    set G(v) {
        this.values[1] = v;
    }
    set B(v) {
        this.values[2] = v;
    }
    set A(v) {
        this.values[3] = v;
    }
    static Equal(c, c2) {
        return (c.R == c2.R && c.G == c2.G && c.B == c2.B && c.A == c2.A);
    }
    toString() {
        return `rgba(${this.R},${this.G},${this.B},${this.A})`;
    }
    Clone() {
        return new Color32(this.R, this.G, this.B, this.A);
    }
}
class ColorF {
    constructor() {
        this.r = 1;
        this.g = 1;
        this.b = 1;
        this.a = 1;
    }
    ToColor32() {
        return new Color32((this.r * 255) | 0, (this.g * 255) | 0, (this.b * 255) | 0, (this.a * 255) | 0);
    }
    static FromH(h360) {
        let c = new ColorF();
        //h360 = 60
        //sin插值
        var v = (h360 % 120 / 120.0);
        if (v < 0)
            v += 1;
        var f = Math.sin(v * Math.PI) * 0.5;
        if (v > 0.5)
            f = 1 - f;
        //直接插值
        //let f = h360 % 120 / 120;
        if (h360 < 120) //b->r
         {
            if (f <= 0.5) {
                c.b = 1.0;
                c.r = (f) / (1 - f);
            }
            else {
                c.r = 1.0;
                c.b = (1 - f) / f;
            }
            c.g = 0;
        }
        else if (h360 < 240) //r->g
         {
            if (f <= 0.5) {
                c.r = 1.0;
                c.g = 1.0 * f / (1 - f);
            }
            else {
                c.g = 1.0;
                c.r = 1.0 * (1 - f) / f;
            }
            c.b = 0;
        }
        else //g->b
         {
            c.r = 0;
            if (f <= 0.5) {
                c.g = 1.0;
                c.b = 1.0 * f / (1 - f);
            }
            else {
                c.b = 1.0;
                c.g = 1.0 * (1 - f) / f;
            }
        }
        return c;
    }
}
class Palette {
    static getNesPal() {
        if (this.nespal == null) {
            this.nespal = [];
            this.nespal.push(new Color32(0, 0, 0, 0));
            this.nespal.push(new Color32(0, 0, 0, 255));
            //把下面的颜色值，均参照上面的格式写，alpha都是255
            this.nespal.push(new Color32(121, 121, 121, 255));
            this.nespal.push(new Color32(162, 162, 162, 255));
            this.nespal.push(new Color32(48, 81, 130, 255));
            this.nespal.push(new Color32(65, 146, 195, 255));
            this.nespal.push(new Color32(97, 211, 227, 255));
            this.nespal.push(new Color32(162, 255, 243, 255));
            this.nespal.push(new Color32(48, 97, 65, 255));
            this.nespal.push(new Color32(73, 162, 105, 255));
            this.nespal.push(new Color32(113, 227, 146, 255));
            this.nespal.push(new Color32(162, 255, 203, 255));
            this.nespal.push(new Color32(56, 109, 0, 255));
            this.nespal.push(new Color32(73, 170, 16, 255));
            this.nespal.push(new Color32(113, 243, 65, 255));
            this.nespal.push(new Color32(162, 243, 162, 255));
            this.nespal.push(new Color32(56, 105, 0, 255));
            this.nespal.push(new Color32(81, 162, 0, 255));
            this.nespal.push(new Color32(154, 235, 0, 255));
            this.nespal.push(new Color32(203, 243, 130, 255));
            this.nespal.push(new Color32(73, 89, 0, 255));
            this.nespal.push(new Color32(138, 138, 0, 255));
            this.nespal.push(new Color32(235, 211, 32, 255));
            this.nespal.push(new Color32(255, 243, 146, 255));
            this.nespal.push(new Color32(121, 65, 0, 255));
            this.nespal.push(new Color32(195, 113, 0, 255));
            this.nespal.push(new Color32(255, 162, 0, 255));
            this.nespal.push(new Color32(255, 219, 162, 255));
            this.nespal.push(new Color32(162, 48, 0, 255));
            this.nespal.push(new Color32(227, 81, 0, 255));
            this.nespal.push(new Color32(255, 121, 48, 255));
            this.nespal.push(new Color32(255, 203, 186, 255));
            this.nespal.push(new Color32(178, 16, 48));
            this.nespal.push(new Color32(219, 65, 97));
            this.nespal.push(new Color32(255, 97, 178));
            this.nespal.push(new Color32(255, 186, 235));
            this.nespal.push(new Color32(154, 32, 121));
            this.nespal.push(new Color32(219, 65, 195));
            this.nespal.push(new Color32(243, 97, 255));
            this.nespal.push(new Color32(227, 178, 255));
            this.nespal.push(new Color32(97, 16, 162));
            this.nespal.push(new Color32(146, 65, 243));
            this.nespal.push(new Color32(162, 113, 255));
            this.nespal.push(new Color32(195, 178, 255));
            this.nespal.push(new Color32(40, 0, 186));
            this.nespal.push(new Color32(65, 65, 255));
            this.nespal.push(new Color32(81, 130, 255));
            this.nespal.push(new Color32(162, 186, 255));
            this.nespal.push(new Color32(32, 0, 178));
            this.nespal.push(new Color32(65, 97, 251));
            this.nespal.push(new Color32(97, 162, 255));
            this.nespal.push(new Color32(146, 211, 255));
            this.nespal.push(new Color32(121, 121, 121));
            this.nespal.push(new Color32(178, 178, 178));
            this.nespal.push(new Color32(235, 235, 235));
            this.nespal.push(new Color32(255, 255, 255));
        }
        return this.nespal;
    }
}

class BaseElement {
    constructor() {
        this.elems = [];
    }
    Show() {
        this._root.style.visibility = "visible";
    }
    Hide() {
        this._root.style.visibility = "hidden";
    }
    getValue() {
        throw new Error("no value.");
    }
    getRoot() {
        return this._root;
    }
    setBackColor(color) {
        this._root.style.backgroundColor = color.toString();
    }
    AddChild(elem) {
        this._root.appendChild(elem.getRoot());
        this.elems.push(elem);
    }
    RemoveAllChild() {
        for (var i = 0; i < this.elems.length; i++) {
            this.elems[i].getRoot().remove();
        }
        this.elems.splice(0);
    }
    RemoveChild(elem) {
        let i = this.elems.indexOf(elem);
        if (i < 0)
            return;
        this.elems.splice(i, 1);
        elem.getRoot().remove();
    }
    RemoveChildAt(index) {
        let elem = this.elems.splice(index, 1)[0];
        elem.getRoot().remove();
    }
    GetChildCount() {
        return this.elems.length;
    }
    GetChild(index) {
        return this.elems[index];
    }
    Style_Fill() {
        this._root.style.position = "absolute";
        this._root.style.left = "0px";
        this._root.style.top = "0px";
        this._root.style.right = "0px";
        this._root.style.bottom = "0px";
        this._root.style.width = "100%";
        this._root.style.height = "100%";
    }
    Style_Size(width, height) {
        this._root.style.width = width + "px";
        this._root.style.height = height + "px";
    }
    Style_Fix(x, y, width, height) {
        this._root.style.position = "absolute";
        this._root.style.left = x + "px";
        this._root.style.top = y + "px";
        this._root.style.right = "auto";
        this._root.style.bottom = "auto";
        this._root.style.width = width + "px";
        this._root.style.height = height + "px";
    }
}
class Screen extends BaseElement {
    constructor() {
        super();
        this._root = document.body;
    }
    getRoot() {
        throw new Error("no root.");
    }
}
class Label extends BaseElement {
    constructor(text = "") {
        super();
        let div = this._root = document.createElement("div");
        this.span = document.createElement("span");
        this.span.textContent = text;
        div.appendChild(this.span);
    }
    getValue() {
        return this.span.innerText;
    }
    getText() {
        return this.span.innerText;
    }
    SetText(text) {
        this.span.innerText = text;
    }
}
class Picture extends BaseElement {
    constructor(url = "") {
        super();
        let img = this._root = document.createElement("img");
        //img.style.position = "absolute";
        img.src = url;
    }
    setSrc(url) {
        this._root.src = url;
    }
    Style_Fill() {
        super.Style_Fill();
        this._root.style.objectFit = "cover";
    }
}
class TextBox extends BaseElement {
    constructor(title, defvalue) {
        super();
        let div = this._root = document.createElement("div");
        this.span = document.createElement("span");
        this.span.textContent = title;
        div.appendChild(this.span);
        this.input = document.createElement("input");
        this.input.value = defvalue;
        this.input.type = "input";
        div.appendChild(this.input);
    }
    setTitle(title) {
        this.span.textContent = title;
    }
    setValue(text) {
        this.input.value = text;
    }
    getValue() {
        return this.input.value;
    }
}
class Toggle extends BaseElement {
    constructor(title, defvalue = false) {
        super();
        let div = this._root = document.createElement("div");
        this.span = document.createElement("span");
        this.span.textContent = title;
        div.appendChild(this.span);
        this.input = document.createElement("input");
        this.input.checked = defvalue;
        this.input.type = "checkbox";
        div.appendChild(this.input);
    }
    setTitle(title) {
        this.span.textContent = title;
    }
    setValue(value) {
        this.input.checked = value;
    }
    getValue() {
        return this.input.checked;
    }
}
class Button extends BaseElement {
    constructor(title, click = null) {
        super();
        let btn = this._root = document.createElement("button");
        btn.innerText = title;
        btn.onclick = click;
    }
    SetText(value) {
        this._root.textContent = value;
    }
    SetClickEvent(click) {
        this._root.onclick = click;
    }
}
class Panel extends BaseElement {
    constructor() {
        super();
        let div = this._root = document.createElement("div");
        //div.style.position = "absolute";
        div.style.border = "1px solid";
        div.style.borderColor = "#fff";
        div.style.color = "#fff";
        div.style.left = "0px";
        div.style.right = "0px";
        div.style.top = "0px";
        div.style.bottom = "0px";
    }
    SetBorder(width) {
        let div = this._root;
        div.style.border = width + "px solid";
    }
    SetVCenter() {
        let div = this._root;
        div.style.top = "50%";
        div.style.position = "relative";
        div.style.transform = "translateY(-50%)";
    }
    UseScrollV() {
        let div = this._root;
        div.style.overflowY = "scroll";
    }
    UseScrollH() {
        let div = this._root;
        div.style.overflowX = "scroll";
    }
}

class Splitter extends Panel {
    constructor() {
        super();
        this.SetBorder(0);
        this._root.style.position = "absolute";
        this._panel1 = new Panel();
        this._panel1.SetBorder(0);
        this._root.appendChild(this._panel1.getRoot());
        this._panel1.getRoot().style.backgroundColor = "#c33";
        this._panel1.getRoot().style.position = "absolute";
        this._panel1.getRoot().style.left = "0px";
        this._panel1.getRoot().style.top = "0px";
        this._panel1.getRoot().style.bottom = "0px";
        this._panel1.getRoot().style.width = "100px";
        this._panel2 = new Panel();
        this._panel2.SetBorder(0);
        this._root.appendChild(this._panel2.getRoot());
        this._panel2.getRoot().style.backgroundColor = "#33c";
        this._panel2.getRoot().style.position = "absolute";
        this._panel2.getRoot().style.left = "100px";
        this._panel2.getRoot().style.top = "0px";
        this._panel2.getRoot().style.bottom = "0px";
        this._panel2.getRoot().style.right = "0px";
    }
    SetSplitPosLeft(pos) {
        this._panel1.getRoot().style.left = "0px";
        this._panel1.getRoot().style.right = "auto";
        this._panel1.getRoot().style.top = "0px";
        this._panel1.getRoot().style.bottom = "0px";
        this._panel1.getRoot().style.width = pos + "px";
        this._panel1.getRoot().style.height = "auto";
        this._panel2.getRoot().style.left = pos + "px";
        this._panel2.getRoot().style.top = "0px";
        this._panel2.getRoot().style.bottom = "0px";
        this._panel2.getRoot().style.right = "0px";
        this._panel2.getRoot().style.width = "auto";
        this._panel2.getRoot().style.height = "auto";
    }
    SetSplitPosRight(pos) {
        this._panel1.getRoot().style.left = "0px";
        this._panel1.getRoot().style.top = "0px";
        this._panel1.getRoot().style.bottom = "0px";
        this._panel1.getRoot().style.right = pos + "px";
        this._panel1.getRoot().style.width = "auto";
        this._panel1.getRoot().style.height = "auto";
        this._panel2.getRoot().style.top = "0px";
        this._panel2.getRoot().style.bottom = "0px";
        this._panel2.getRoot().style.left = "auto";
        this._panel2.getRoot().style.right = "0px";
        this._panel2.getRoot().style.width = pos + "px";
        this._panel1.getRoot().style.height = "auto";
    }
    SetSplitPosTop(pos) {
        this._panel1.getRoot().style.left = "0px";
        this._panel1.getRoot().style.bottom = "auto";
        this._panel1.getRoot().style.top = "0px";
        this._panel1.getRoot().style.right = "0px";
        this._panel1.getRoot().style.height = pos + "px";
        this._panel1.getRoot().style.width = "auto";
        this._panel2.getRoot().style.top = pos + "px";
        this._panel2.getRoot().style.left = "0px";
        this._panel2.getRoot().style.bottom = "0px";
        this._panel2.getRoot().style.right = "0px";
        this._panel2.getRoot().style.width = "auto";
        this._panel2.getRoot().style.height = "auto";
    }
    SetSplitPosBottom(pos) {
        this._panel1.getRoot().style.left = "0px";
        this._panel1.getRoot().style.bottom = pos + "px";
        this._panel1.getRoot().style.top = "0px";
        this._panel1.getRoot().style.right = "0px";
        this._panel1.getRoot().style.height = "auto";
        this._panel1.getRoot().style.width = "auto";
        this._panel2.getRoot().style.top = "auto";
        this._panel2.getRoot().style.left = "0px";
        this._panel2.getRoot().style.bottom = "0px";
        this._panel2.getRoot().style.right = "0px";
        this._panel2.getRoot().style.width = "auto";
        this._panel2.getRoot().style.height = pos + "px";
    }
    AddChild(elem) {
        throw new Error("use left or right");
    }
}

class Group extends Panel {
    constructor() {
        super();
        this._root.style.position = "absolute";
        this._label = new Label("group");
        this._root.appendChild(this._label.getRoot());
        this._label.getRoot().style.position = "absolute";
        this._label.getRoot().style.left = "0px";
        this._label.getRoot().style.right = "0px";
        this._label.getRoot().style.top = "0px";
        this._label.getRoot().style.height = "20px";
        this._panel = new Panel();
        this._root.appendChild(this._panel.getRoot());
        this._panel.getRoot().style.position = "absolute";
        this._panel.getRoot().style.left = "0px";
        this._panel.getRoot().style.right = "0px";
        this._panel.getRoot().style.top = "20px";
        this._panel.getRoot().style.bottom = "0px";
    }
    SetTitle(title) {
        this._label.SetText(title);
    }
    AddChild(elem) {
        throw new Error("use panel");
    }
}

class Canvas extends BaseElement {
    constructor() {
        super();
        this._root = document.createElement("canvas");
        this._root.style.left = "0px";
        this._root.style.right = "0px";
        this._root.style.top = "0px";
        this._root.style.bottom = "0px";
        this._root.style.position = "absolute";
        this._root.style.width = "100%";
        this._root.style.height = "100%";
        this._c2d = this._root.getContext("2d");
        window.addEventListener("resize", () => {
            this.Refresh();
        });
        // this._root.addEventListener("resize", () => {
        //   
        // });
    }
    Refresh() {
        this._c2d.canvas.width = this._root.clientWidth;
        this._c2d.canvas.height = this._root.clientHeight;
        if (this.RePaint != null)
            this.RePaint(this._c2d);
    }
    getC2D() {
        return this._c2d;
    }
}

class RangeBar extends BaseElement {
    get min() {
        return this._min;
    }
    set min(v) {
        this._min = v;
        this._input.min = this._min.toString();
        this._input.max = this._max.toString();
    }
    get max() {
        return this._max;
    }
    set max(v) {
        this._max = v;
        this._input.min = this._min.toString();
        this._input.max = this._max.toString();
    }
    getValue() {
        return this._input.valueAsNumber | 0;
    }
    valueAdd() {
        let value = parseFloat(this._input.value) | 0;
        if (this.usestepmode) {
            for (var i = 1; i <= 8; i++) {
                let v = Math.pow(2, i - 1);
                let vbig = Math.pow(2, i);
                if (v <= value && value < vbig) {
                    value = vbig;
                    break;
                }
            }
        }
        else {
            value++;
        }
        if (value > this.max)
            value = this.max;
        this.changeValue(value);
    }
    valueDec() {
        let value = parseFloat(this._input.value) | 0;
        if (this.usestepmode) {
            for (var i = 8; i > 0; i--) {
                let v = Math.pow(2, i);
                let vsmall = Math.pow(2, i - 1);
                if (vsmall < value && value <= v) {
                    value = vsmall;
                    break;
                }
            }
        }
        else {
            value--;
        }
        if (value < this.min)
            value = this.min;
        this.changeValue(value);
    }
    constructor() {
        super();
        this._min = 1;
        this._max = 64;
        this.usestepmode = true; //阶乘式变化数值
        this._root = document.createElement("div");
        this.Style_Fill();
        let btnleft = new Button("◀");
        btnleft._root.style.position = "absolute";
        btnleft._root.style.width = "24px";
        btnleft._root.style.height = "24px";
        let btnright = new Button("▶");
        btnright._root.style.position = "absolute";
        btnright._root.style.width = "24px";
        btnright._root.style.height = "24px";
        btnright._root.style.right = "0px";
        let input = this._input = document.createElement("input");
        input.style.position = "absolute";
        input.style.left = "24px";
        input.style.height = "24px";
        input.style.right = "60px";
        input.type = "range";
        input.min = this._min.toString();
        input.max = this._max.toString();
        input.onchange = () => {
            let value = parseFloat(this._input.value) | 0;
            this.changeValue(value);
        };
        this._label = document.createElement("span");
        this._label.style.position = "absolute";
        this._label.style.width = "36px";
        this._label.style.height = "24px";
        this._label.style.right = "24px";
        this.getRoot().appendChild(btnleft.getRoot());
        this.getRoot().appendChild(input);
        this.getRoot().appendChild(this._label);
        this.getRoot().appendChild(btnright.getRoot());
        btnleft._root.onclick = () => {
            this.valueDec();
        };
        btnright._root.onclick = () => {
            this.valueAdd();
        };
        this.changeValue(1);
    }
    changeValue(v) {
        if (v > this.max)
            v = this.max;
        if (v < this.min)
            v = this.min;
        this._input.value = v.toString();
        this._label.textContent = "X" + v.toString();
        if (this.onchange != null)
            this.onchange(v);
    }
}

class Preview extends Panel {
    getScale() {
        return this._range.getValue();
    }
    constructor() {
        super();
        this.rectX = 0;
        this.rectY = 0;
        this.rectWidth = 100;
        this.rectHeight = 100;
        this.imgradio = 1;
        this._inref = false;
        this._bordercolor = new Color32(255, 255, 255, 255);
        {
            this.Style_Fill();
            this.SetBorder(1);
            this._panel = new Panel();
            this._panel.SetBorder(1);
            this._panel._root.style.position = "absolute";
            this._panel._root.style.left = "0px";
            this._panel._root.style.top = "0px";
            this._panel._root.style.right = "0px";
            this._panel._root.style.bottom = "auto";
            this._panel._root.style.width = "auto";
            this._panel._root.style.height = "auto";
            this._panel._root.style.aspectRatio = "1/1";
            this._root.appendChild(this._panel.getRoot());
            let bar = this._range = new RangeBar();
            bar._root.style.top = "auto";
            bar._root.style.height = "24px";
            this._root.appendChild(bar.getRoot());
            bar.onchange = (v) => {
                if (this.onChangeScale != null)
                    this.onChangeScale(v);
            };
            // this._img = new Picture("");
            //  this._canvas._root.style.width = "100%";
            //  this._canvas._root.style.height = "100%";
            //  this._canvas._root.style.backgroundColor = "#000";
            //  this._canvas.Fill();
            // this._img._root.onload = () => {
            //     this.Refresh();
            // }
            // this._panel.AddChild(this._img);
            this._canvas = new Canvas();
            this._canvas.Style_Fill();
            this._canvas._root.style.width = "100%";
            this._canvas._root.style.height = "100%";
            //this._canvas._root.style.backgroundColor = "#000";
            this._canvas.RePaint = this.RePaint.bind(this);
            this._panel.AddChild(this._canvas);
            let press = false;
            let _elayer = this._canvas.getRoot();
            _elayer.onmousedown = (e) => {
                e.clientX;
                e.clientY;
                press = true;
            };
            _elayer.onmousemove = (e) => {
                if (press) {
                    //处理点在红框之外
                    let fh = _elayer.clientHeight;
                    let scale = fh / this.imgheight;
                    if (this.rectX < e.offsetX / scale - this.rectWidth)
                        this.rectX = e.offsetX / scale - this.rectWidth;
                    if (this.rectY < e.offsetY / scale - this.rectHeight)
                        this.rectY = e.offsetY / scale - this.rectHeight;
                    if (this.rectX > e.offsetX / scale)
                        this.rectX = e.offsetX / scale;
                    if (this.rectY > e.offsetY / scale)
                        this.rectY = e.offsetY / scale;
                    //移动红框
                    this.rectX += e.movementX / scale;
                    this.rectY += e.movementY / scale;
                    //不让红框离开canvas
                    if (this.rectX > this.imgwidth - this.rectWidth)
                        this.rectX = this.imgwidth - this.rectWidth;
                    if (this.rectY > this.imgheight - this.rectHeight)
                        this.rectY = this.imgheight - this.rectHeight;
                    if (this.rectX < 0)
                        this.rectX = 0;
                    if (this.rectY < 0)
                        this.rectY = 0;
                    this.Refresh();
                }
            };
            window.addEventListener("mouseup", (e) => {
                press = false;
            });
        }
    }
    SetImg(img) {
        this.imgheight = img.getHeight();
        this.imgwidth = img.getWidth();
        this.imgradio = img.getWidth() / img.getHeight();
        this._rt = img;
        this.Refresh();
        //this._img.setSrc(img.src);
    }
    UpdateImgSize() {
        let img = this._rt;
        console.log("update img size.");
        this.imgheight = img.getHeight();
        this.imgwidth = img.getWidth();
        this.imgradio = img.getWidth() / img.getHeight();
        let r = this._panel._root.clientWidth / this._panel._root.clientHeight;
        let w = this._panel._root.clientWidth;
        let h = this._panel._root.clientHeight;
        let rimg = this.imgradio;
        if (rimg < r) {
            this._canvas._root.style.height = h + "px";
            this._canvas._root.style.width = (h * rimg) + "px";
            this._canvas._root.style.left = ((w - rimg * h) / 2) + "px";
            this._canvas._root.style.top = "0px";
            this._canvas._root.style.right = "auto";
            this._canvas._root.style.bottom = "auto";
            let c = this._canvas._root;
            c.width = h * rimg;
            c.height = h;
        }
        else {
            this._canvas._root.style.width = w + "px";
            this._canvas._root.style.height = (w / rimg) + "px";
            this._canvas._root.style.left = "0px"; // ((w - rimg * h) / 2) + "px";
            this._canvas._root.style.top = ((h - w / rimg) / 2) + "px";
            this._canvas._root.style.right = "auto";
            this._canvas._root.style.bottom = "auto";
            let c = this._canvas._root;
            c.width = w;
            c.height = w / rimg;
        }
        this.Refresh();
    }
    ;
    Refresh() {
        this._canvas.Refresh();
        //处理点在红框之外
        if (this.rectX > this.imgwidth - this.rectWidth)
            this.rectX = this.imgwidth - this.rectWidth;
        if (this.rectY > this.imgheight - this.rectHeight)
            this.rectY = this.imgheight - this.rectHeight;
        if (this.rectX < 0)
            this.rectX = 0;
        if (this.rectY < 0)
            this.rectY = 0;
        //防事件递归
        if (this._inref == true)
            return;
        if (this.onChange != null) {
            this._inref = true;
            this.onChange();
            this._inref = false;
        }
    }
    setBackColor(color) {
        this._canvas.setBackColor(color);
        //super.setBackColor(color);
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            this._bordercolor.R = 255;
            this._bordercolor.G = 255;
            this._bordercolor.B = 255;
        }
        else {
            this._bordercolor.R = 0;
            this._bordercolor.G = 0;
            this._bordercolor.B = 0;
        }
        this.Refresh();
    }
    RePaint(c2d) {
        this._canvas._c2d.imageSmoothingEnabled = false;
        //refix imgsize
        let r = this._panel._root.clientWidth / this._panel._root.clientHeight;
        let w = this._panel._root.clientWidth;
        let h = this._panel._root.clientHeight;
        let rimg = this.imgradio;
        let fw = 0;
        let fh = 0;
        if (rimg < r) {
            fh = h;
            fw = h * rimg;
            this._canvas._root.style.height = h + "px";
            this._canvas._root.style.width = (h * rimg) + "px";
            this._canvas._root.style.left = ((w - rimg * h) / 2) + "px";
            this._canvas._root.style.top = "0px";
            this._canvas._root.style.right = "auto";
            this._canvas._root.style.bottom = "auto";
        }
        else {
            fw = w;
            fh = w / rimg;
            this._canvas._root.style.width = w + "px";
            this._canvas._root.style.height = (w / rimg) + "px";
            this._canvas._root.style.left = "0px"; // ((w - rimg * h) / 2) + "px";
            this._canvas._root.style.top = ((h - w / rimg) / 2) + "px";
            this._canvas._root.style.right = "auto";
            this._canvas._root.style.bottom = "auto";
        }
        if (this._rt != null) {
            let img = this._rt.getBitmap();
            //let c = this._canvas._root as HTMLCanvasElement;
            c2d.drawImage(img, 0, 0, img.width, img.height, 0, 0, fw, fh);
        }
        c2d.strokeStyle = this._bordercolor.toString();
        let scale = fh / this.imgheight;
        c2d.lineWidth = 4;
        c2d.strokeRect(this.rectX * scale, this.rectY * scale, this.rectWidth * scale, this.rectHeight * scale);
    }
}

class PalettePanel extends BaseElement {
    constructor() {
        super();
        this.blocksize = 20;
        //blockcount: number = 80;
        this.colors = [];
        this.pickindex = 1;
        this.pickindexhide = 3;
        this._root = document.createElement("div");
        this._root.style.fontSize = "0";
        this.Style_Fill();
        this.InitDefPal();
        while (this.colors.length < 80) {
            this.colors.push(new Color32(0, 0, 0, 255));
        }
        this.Update();
    }
    InitDefPal() {
        let pal = Palette.getNesPal();
        for (var i = 0; i < pal.length; i++) {
            this.colors.push(pal[i].Clone());
        }
        // if (this.blockcount < this.colors.length)
        //     this.blockcount = this.colors.length;
        this.colors[0].A = 0;
        this.Update();
    }
    Update() {
        let blockcount = this.colors.length;
        if (this.pickindex >= blockcount)
            this.pickindex = 0;
        //数量准备
        while (this._root.childElementCount < blockcount) {
            let div = document.createElement("div");
            div.style.display = "inline-block";
            div.style.width = this.blocksize + "px";
            div.style.height = this.blocksize + "px";
            div.style.border = "2px solid #ccc";
            div.style.position = "relative";
            this._root.appendChild(div);
        }
        while (this._root.childElementCount > blockcount) {
            this._root.children[this._root.childElementCount - 1].remove();
        }
        for (var i = 0; i < blockcount; i++) {
            let div = this._root.children[i];
            div.title = i == 0 ? "透明色/擦除" : this.colors[i].toString();
            div.style.backgroundColor = this.colors[i].toString();
            if (this.pickindex == i) {
                div.style.border = "2px solid #fff";
            }
            else {
                div.style.border = "2px solid #000";
            }
            let index = i;
            div.onmousedown = (e) => {
                if (e.ctrlKey) {
                    this.pickindexhide = index;
                }
                else if (e.button == 0) {
                    this.pickindex = index;
                    this.Update();
                }
                if (this.onPick != null) {
                    this.onPick(this.pickindex, this.pickindexhide);
                }
            };
        }
    }
}

var __awaiter$6 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class TTPathTool {
    static GetFileName(filename) {
        if (filename.includes("/")) {
            let fi = filename.lastIndexOf("/");
            let shortname = filename.substring(fi + 1);
            return shortname;
        }
        if (filename.includes("\\")) {
            let fi = filename.lastIndexOf("\\");
            let shortname = filename.substring(fi + 1);
            return shortname;
        }
        return filename;
    }
    static GetPathName(filename) {
        if (filename.includes("/")) {
            let fi = filename.lastIndexOf("/");
            if (fi < 0)
                return filename;
            let shortname = filename.substring(0, fi);
            return shortname;
        }
        if (filename.includes("\\")) {
            let fi = filename.lastIndexOf("\\");
            let shortname = filename.substring(0, fi);
            return shortname;
        }
        return "";
    }
    static GetFileNameWithoutExt(filename) {
        let shortname = this.GetFileName(filename);
        let di = shortname.indexOf(".");
        if (di < 0)
            return shortname;
        return shortname.substring(0, di);
    }
    static GetExt(filename) {
        let shortname = this.GetFileName(filename);
        console.log("_getext:" + shortname);
        let di = shortname.indexOf(".");
        if (di < 0)
            return "";
        return shortname.substring(di);
    }
}
class IO {
    static GetPluginUrl(suburl) {
        let subl = suburl;
        if (suburl[0] == "/")
            subl = suburl.substring(1);
        else
            subl = suburl;
        return this.baseurl + subl;
    }
    static Init() {
        window.onmessage = (msg) => {
            if (msg.data["cmd"] != undefined) {
                //console.log("recv:" + JSON.stringify(msg));//.data["cmd"];
                this.dataqueue.push(msg.data);
            }
        };
        this.api = acquireVsCodeApi();
        this.baseurl = getVsCodePluginPath();
        if (this.baseurl.endsWith("/") == false) {
            this.baseurl += "/";
        }
        this.editfile = getVsCodeEditFileName(); //得到编辑的文件名
    }
    static GetEditFileName() {
        return this.editfile;
    }
    static GetEditBaseName() {
        return TTPathTool.GetFileNameWithoutExt(this.editfile);
    }
    static Hex2Str(data) {
        let str = "";
        for (var i = 0; i < data.length; i++) {
            let h = data[i].toString(16);
            if (h.length == 1) {
                str += ("0" + h);
            }
            else {
                str += h;
            }
        }
        return str;
    }
    static Str2Hex(text) {
        let u8 = new Uint8Array(text.length / 2);
        for (var i = 0; i < u8.length; i++) {
            let h = text.substring(i * 2, i * 2 + 2);
            u8[i] = parseInt(h, 16);
        }
        return u8;
    }
    static getBaseUrl() {
        return this.baseurl;
    }
    static getEditFile() {
        return this.editfile;
    }
    static sleep(ms) {
        return __awaiter$6(this, void 0, void 0, function* () {
            return new Promise(resolve => setTimeout(resolve, ms));
        });
    }
    static LoadEditFile_AsText() {
        return __awaiter$6(this, void 0, void 0, function* () {
            return yield this.LoadTextFile(this.editfile);
        });
    }
    static FindFile(path, depth = 1) {
        return __awaiter$6(this, void 0, void 0, function* () {
            let sname = path;
            while (sname.includes("\\")) {
                sname = sname.replace("\\", "/");
            }
            this.api.postMessage({ "cmd": "fs_find", "data": { "depth": depth, "path": path } });
            while (true) {
                yield this.sleep(1);
                for (var i = 0; i < this.dataqueue.length; i++) {
                    let q = this.dataqueue[i];
                    if (q["cmd"] == "filelist") {
                        let fname = q["path"];
                        while (fname.includes("\\")) {
                            fname = fname.replace("\\", "/");
                        }
                        if (fname == sname) {
                            let text = q["data"];
                            this.dataqueue.splice(i, 1);
                            return text;
                        }
                    }
                    if (q["cmd"] == "onerror" && q["srccmd"] == "filelist") {
                        console.error(JSON.stringify(q));
                        throw new Error(JSON.stringify(q));
                    }
                }
            }
        });
    }
    static LoadTextFile(name) {
        return __awaiter$6(this, void 0, void 0, function* () {
            let sname = name;
            while (sname.includes("\\")) {
                sname = sname.replace("\\", "/");
            }
            this.api.postMessage({ "cmd": "fs_load_text", "data": name });
            while (true) {
                yield this.sleep(1);
                for (var i = 0; i < this.dataqueue.length; i++) {
                    let q = this.dataqueue[i];
                    if (q["cmd"] == "filedata") {
                        let fname = q["filename"];
                        while (fname.includes("\\")) {
                            fname = fname.replace("\\", "/");
                        }
                        if (fname == sname) {
                            let text = q["data"];
                            this.dataqueue.splice(i, 1);
                            return text;
                        }
                    }
                    if (q["cmd"] == "onerror" && q["srccmd"] == "fs_load_text") {
                        console.error(JSON.stringify(q));
                        throw new Error(JSON.stringify(q));
                    }
                }
            }
        });
    }
    static LoadBinaryFile(name) {
        return __awaiter$6(this, void 0, void 0, function* () {
            let sname = name;
            while (sname.includes("\\")) {
                sname = sname.replace("\\", "/");
            }
            this.api.postMessage({ "cmd": "fs_load_binary", "data": name });
            while (true) {
                yield this.sleep(1);
                for (var i = 0; i < this.dataqueue.length; i++) {
                    let q = this.dataqueue[i];
                    if (q["cmd"] == "filedata") {
                        let fname = q["filename"];
                        while (fname.includes("\\")) {
                            fname = fname.replace("\\", "/");
                        }
                        if (fname == sname) {
                            this.dataqueue.splice(i, 1);
                            let hex = q["data"];
                            return this.Str2Hex(hex);
                        }
                    }
                    if (q["cmd"] == "onerror" && q["srccmd"] == "fs_load_binary") {
                        console.error(JSON.stringify(q));
                        throw new Error(JSON.stringify(q));
                    }
                }
            }
        });
    }
    static SaveBinaryFile(name, data) {
        return __awaiter$6(this, void 0, void 0, function* () {
            this.api.postMessage({ "cmd": "fs_save_binary", "data": { "data": this.Hex2Str(data), "filename": name } });
        });
    }
    static SaveTextFile(name, data) {
        return __awaiter$6(this, void 0, void 0, function* () {
            this.api.postMessage({ "cmd": "fs_save_text", "data": { "data": data, "filename": name } });
        });
    }
}
IO.dataqueue = [];

class Toolbar extends BaseElement {
    constructor() {
        super();
        this.btnsize = 28;
        this.mapHtml = null;
        this._root = document.createElement("div");
        this._root.style.fontSize = "0";
        this.Style_Fill();
    }
    getPickTag() {
        return this._picktag;
    }
    getPickImg() {
        if (this.mapHtml == null || this.mapHtml[this._picktag] == null)
            return null;
        return this.mapHtml[this._picktag].children[0];
    }
    setPickTag(tag) {
        if (this.mapHtml[tag] != null) {
            this._picktag = tag;
            this.Update();
            return true;
        }
        return false;
    }
    clearButton() {
        this.mapHtml = {};
        while (this._root.children.length > 0) {
            this._root.children[this._root.children.length - 1].remove();
        }
    }
    addButton(iconurl, picktag, tips, color = null) {
        let div = document.createElement("div");
        div.style.display = "inline-block";
        div.style.width = this.btnsize + "px";
        div.style.height = this.btnsize + "px";
        div.style.border = "2px solid #ccc";
        div.style.position = "relative";
        div.style.border = "2px solid #000";
        if (color != null) {
            div.style.backgroundColor = color;
        }
        if (this.mapHtml == null) {
            this.mapHtml = {};
            this._picktag = picktag;
            div.style.border = "2px solid #fff";
        }
        this.mapHtml[picktag] = div;
        let img = new Picture();
        img.Style_Fill();
        img._root.style.objectFit = "contain";
        div.appendChild(img._root);
        let url = iconurl;
        if (url.includes("://") == false) {
            url = IO.GetPluginUrl(iconurl);
        }
        img.setSrc(url);
        img._root.title = tips;
        img._root.onmousedown = () => {
            this._picktag = picktag;
            this.Update();
        };
        this._root.appendChild(div);
    }
    Update() {
        for (var key in this.mapHtml) {
            if (key == this._picktag) {
                this.mapHtml[key].style.border = "2px solid #fff";
            }
            else {
                this.mapHtml[key].style.border = "2px solid #000";
            }
        }
        if (this.onPick != null) {
            this.onPick(this._picktag);
        }
    }
}

//Menu 这玩意儿 为什么要我自己搞一个，html没现成的吗？
class Menu {
    constructor() {
        this._divMenu = document.createElement("div");
        this._divMenu.style.position = "absolute";
        this._divMenu.style.left = "0px";
        this._divMenu.style.right = "0px";
        this._divMenu.style.top = "0px";
        this._divMenu.style.bottom = "0px";
        //this._divMenu.style.backgroundColor = "rgba(0,0,0,0.5)";
        document.body.appendChild(this._divMenu);
        this._divMenu.hidden = true;
        this._divMenu.addEventListener("mousedown", () => {
            this.Close();
        });
    }
    AddItem(title, click = null) {
        if (this._context == null)
            this._context = new MenuContent(this);
        this._context.AddItem(title, click);
    }
    Show(x, y) {
        document.body.appendChild(this._divMenu);
        this._divMenu.hidden = false;
        if (this._context != null) {
            this._context.Show(x, y);
        }
    }
    Close() {
        while (this._divMenu.children.length > 0) {
            this._divMenu.children[0].remove();
        }
        this._divMenu.hidden = true;
    }
    GetElemCenter(elem) {
        let rect = elem.getBoundingClientRect();
        return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
    }
}
class MenuContent {
    constructor(_menu) {
        this._submenu = {};
        this._menu = _menu;
        this._divBack = document.createElement("div");
        this._divBack.style.position = "absolute";
        this._divBack.style.left = "0px";
        this._divBack.style.right = "0px";
        this._divBack.style.top = "0px";
        this._divBack.style.bottom = "0px";
        this._divBack.style.backgroundColor = "rgba(0,0,0,0.5)";
        this._div = document.createElement("div");
        this._div.style.position = "absolute";
        this._div.style.left = "0px";
        this._div.style.right = "0px";
        this._div.style.width = "200px";
        this._div.style.height = "auto";
        this._divBack.appendChild(this._div);
        this._divBack.addEventListener("mousedown", () => {
            this._menu.Close();
        });
    }
    Show(x, y) {
        this._menu._divMenu.appendChild(this._divBack);
        this._div.style.left = x + "px";
        this._div.style.top = y + "px";
    }
    AddItem(title, click) {
        if (title.includes("/")) {
            let iname = title.indexOf("/");
            let name = title.substring(0, iname);
            if (this._submenu[name] == null) {
                let mc = new MenuContent(this._menu);
                this._submenu[name] = mc;
                mc = this._submenu[name];
                //new
                let btn = document.createElement("a");
                this._div.appendChild(btn);
                var br = document.createElement("br");
                this._div.appendChild(br);
                btn.textContent = name + "->";
                btn.onmousedown = (e) => {
                    e.stopPropagation();
                };
                btn.onclick = (e) => {
                    console.log("submenu down.");
                    let pos = this._menu.GetElemCenter(btn);
                    mc.Show(pos.x, pos.y);
                };
            }
            let restname = title.substring(iname + 1);
            this._submenu[name].AddItem(restname, click);
            return;
        }
        //特殊显示规则
        if (title[0] == "_" || title[0] == "-") {
            if (title.length == 1) {
                let br = document.createElement("hr");
                this._div.appendChild(br);
                return;
            }
            let span = document.createElement("span");
            span.textContent = title.substring(1);
            let br = document.createElement("br");
            this._div.appendChild(span);
            this._div.appendChild(br);
            return;
        }
        //没实现
        if (click == null) {
            let span = document.createElement("span");
            span.textContent = "*" + title + "*";
            let br = document.createElement("br");
            this._div.appendChild(span);
            this._div.appendChild(br);
            return;
        }
        let btn = document.createElement("button");
        this._div.appendChild(btn);
        var br = document.createElement("br");
        this._div.appendChild(br);
        btn.textContent = title;
        btn.onmousedown = (e) => {
            e.stopPropagation();
        };
        btn.onclick = (e) => {
            console.log("btn down.");
            if (click != null)
                click(btn);
            this._menu.Close();
        };
    }
}

class Vector2 {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    static add(a, b) { return new Vector2(a.x + b.x, a.y + b.y); }
    static dot(a, b) { return a.x * b.x + a.y * b.y; }
    static cross(a, b) { return a.x * b.y - a.y * b.x; }
    static sub(a, b) { return new Vector2(a.x - b.x, a.y - b.y); }
    static getLength(a) { return Math.sqrt(a.x * a.x + a.y * a.y); }
    static normalize(a) {
        let len = Vector2.getLength(a);
        return new Vector2(a.x / len, a.y / len);
    }
}

class PaletteRGBPanel extends BaseElement {
    constructor() {
        super();
        this.ringmin = 100;
        this.ringmax = 128;
        this.rectSize = 128;
        this._press = 0;
        this.h = 0; //h取值0~1
        this.s = 1;
        this.v = 1;
        let canvas = this._root = document.createElement("canvas");
        this.Style_Fill();
        this.c2d = canvas.getContext("2d");
        canvas.onmousedown = (e) => {
            this.OnMouseDown(e.offsetX, e.offsetY);
        };
        canvas.onmousemove = (e) => {
            if (this._press == 1)
                this.resetH(e.offsetX, e.offsetY);
            else if (this._press == 2)
                this.resetSV(e.offsetX, e.offsetY);
        };
        window.addEventListener("mouseup", (e) => {
            this._press = 0;
        });
        this.update();
    }
    getPickColor() {
        let c = ColorF.FromH(this.h * 360);
        let overbright = (1.0 - this.s);
        c.r = c.r * (1 - overbright) + overbright;
        c.g = c.g * (1 - overbright) + overbright;
        c.b = c.b * (1 - overbright) + overbright;
        let bright = (this.v);
        c.r *= bright;
        c.g *= bright;
        c.b *= bright;
        return c;
    }
    OnMouseDown(offx, offy) {
        let dx = offx / this.c2d.canvas.clientWidth * 2 - 1;
        let dy = offy / this.c2d.canvas.clientHeight * 2 - 1;
        dx *= 128;
        dy *= 128;
        let dir = new Vector2(dx, dy);
        let len = Vector2.getLength(dir);
        if (len > this.ringmin && len < this.ringmax) {
            this.resetH(offx, offy);
            this._press = 1; //pick h
        }
        else if (len <= this.ringmin) {
            this.resetSV(offx, offy);
            this._press = 2;
        }
    }
    resetSV(offx, offy) {
        let dx = offx / this.c2d.canvas.clientWidth * 2 - 1;
        let dy = offy / this.c2d.canvas.clientHeight * 2 - 1;
        dx *= 128;
        dy *= 128;
        let rsize = (this.rectSize / 2);
        let s = (dx + rsize) / this.rectSize;
        let v = 1.0 - (dy + rsize) / this.rectSize;
        if (s < 0)
            s = 0;
        if (v < 0)
            v = 0;
        if (s > 1)
            s = 1;
        if (v > 1)
            v = 1;
        this.s = s;
        this.v = v;
        this.update();
    }
    resetH(offx, offy) {
        let dx = offx / this.c2d.canvas.clientWidth * 2 - 1;
        let dy = offy / this.c2d.canvas.clientHeight * 2 - 1;
        dx *= 128;
        dy *= 128;
        let dir = new Vector2(dx, dy);
        dir = Vector2.normalize(dir);
        let cross = Vector2.dot(dir, new Vector2(-1, 0));
        let angle = Math.acos(cross) / Math.PI * 180;
        if (dir.y > 0) {
            angle = 360 - angle;
        }
        this.h = angle / 360;
        //console.log("h=" + this.h);
        this.update();
    }
    update() {
        this.c2d.canvas.width = 256;
        this.c2d.canvas.height = 256;
        this.c2d.clearRect(0, 0, 256, 256);
        var imgrect = new ImageData(256, 256);
        //画色环
        this.setHRing(imgrect, this.ringmin, this.ringmax);
        //画中心色
        this.setColorRect(imgrect, this.rectSize);
        this.c2d.putImageData(imgrect, 0, 0);
        //画当前选中H
        this.DrawPickH((this.ringmin + this.ringmax) / 2);
        this.DrawPickSV(this.rectSize);
        let pickc = this.getPickColor().ToColor32();
        this._root.style.backgroundColor = pickc.toString();
        if (this.onPick != null)
            this.onPick(pickc);
    }
    DrawPickH(r) {
        let cos = Math.cos(this.h * Math.PI * 2);
        let sin = Math.sin(this.h * Math.PI * 2);
        let x = -cos * r + 128;
        let y = -sin * r + 128;
        this.c2d.strokeStyle = "#fff";
        this.c2d.lineWidth = 3;
        this.c2d.beginPath();
        this.c2d.arc(x, y, 8, 0, Math.PI * 2);
        this.c2d.closePath();
        this.c2d.stroke();
    }
    DrawPickSV(size) {
        let x = 128 - size / 2 + size * this.s;
        let y = 128 - size / 2 + size * (1 - this.v);
        this.c2d.strokeStyle = "#fff";
        this.c2d.lineWidth = 3;
        this.c2d.beginPath();
        this.c2d.arc(x, y, 8, 0, Math.PI * 2);
        this.c2d.closePath();
        this.c2d.stroke();
    }
    setHRing(imgrect, minr, maxr) {
        for (var y = 0; y < 256; y++) {
            for (var x = 0; x < 256; x++) {
                let dir = new Vector2(x - 128, y - 128);
                let len = Vector2.getLength(dir);
                if (len > maxr)
                    continue;
                if (len < minr)
                    continue;
                dir = Vector2.normalize(dir);
                let cross = Vector2.dot(dir, new Vector2(-1, 0));
                let angle = Math.acos(cross) / Math.PI * 180;
                if (dir.y > 0) {
                    angle = 360 - angle;
                }
                //console.log(angle);
                let seek = (y * 256 + x) * 4;
                let color = ColorF.FromH(angle).ToColor32();
                imgrect.data[seek + 0] = color.R;
                imgrect.data[seek + 1] = color.G;
                imgrect.data[seek + 2] = color.B;
                imgrect.data[seek + 3] = 255;
            }
        }
    }
    setColorRect(imgrect, size) {
        let color = ColorF.FromH(this.h * 360);
        //.ToColor32();
        for (var y = 0; y < size; y++) {
            for (var x = 0; x < size; x++) {
                let dx = 128 + x - size / 2;
                let dy = 128 + y - size / 2;
                let seek = (dy * 256 + dx) * 4;
                let r = color.r;
                let g = color.g;
                let b = color.b;
                let overbright = (1 - x / size);
                r = r * (1 - overbright) + overbright;
                g = g * (1 - overbright) + overbright;
                b = b * (1 - overbright) + overbright;
                let bright = (1 - y / size);
                r *= bright;
                g *= bright;
                b *= bright;
                imgrect.data[seek + 0] = r * 255;
                imgrect.data[seek + 1] = g * 255;
                imgrect.data[seek + 2] = b * 255;
                imgrect.data[seek + 3] = 255;
            }
        }
    }
}

class DomTool {
    static Init() {
        document.body.style.backgroundColor = "#000";
        document.body.style.color = "#fff";
        this.screen = new Screen();
    }
    static InitFullScreen() {
        document.body.style.backgroundColor = "#000";
        document.body.style.color = "#fff";
        document.body.style.width = "100%";
        document.body.style.height = "100%";
        document.body.style.position = "absolute";
        document.body.style.margin = "0px";
        document.body.style.padding = "0px";
        document.body.style.overflow = "hidden";
        document.body.style.transform = "scale(1,1)";
        document.body.style.userSelect = "none";
        window.addEventListener('mousewheel', function (e) {
            e = e || window.event;
            if ((e.wheelDelta && event.ctrlKey) || e.detail) {
                event.preventDefault();
            }
        }, { capture: false, passive: false });
        window.addEventListener('keydown', function (event) {
            if ((event.ctrlKey === true || event.metaKey === true)
                && (event.keyCode === 61 || event.keyCode === 107
                    || event.keyCode === 173 || event.keyCode === 109
                    || event.keyCode === 187 || event.keyCode === 189)) {
                event.preventDefault();
            }
        }, false);
        window.addEventListener('touchmove', function (event) {
            event.preventDefault();
        }, { passive: false });
        window.addEventListener('dragstart', function (event) {
            event.preventDefault();
        }, false);
        window.addEventListener("contextmenu", (e) => {
            e.preventDefault();
            return false;
        });
        window.addEventListener("mousedown", function (event) {
            if (event.button == 2) {
                event.preventDefault();
            }
        });
        this.screen = new Screen();
    }
    static AddPanel() {
        let div = new Panel();
        this.screen.AddChild(div);
        return div;
    }
    static AddLabel(text) {
        let label = new Label(text);
        this.screen.AddChild(label);
        return label;
    }
    static AddTextBox(title, deftext) {
        let text = new TextBox(title, deftext);
        this.screen.AddChild(text);
        return text;
    }
    static AddButton(text, onclick = null) {
        let btn = new Button(text);
        btn.SetClickEvent(onclick);
        this.screen.AddChild(btn);
        return btn;
    }
    static AddToggle(title, value) {
        let toggle = new Toggle(title, value);
        this.screen.AddChild(toggle);
        return toggle;
    }
    static AddSpliter() {
        let s = new Splitter();
        document.body.appendChild(s.getRoot());
        return s;
    }
}

class Rectangle {
    /**
     * Creates an instance of Rectangle.
     *
     * @param {number} [width=0]
     * @param {number} [height=0]
     * @param {number} [x=0]
     * @param {number} [y=0]
     * @param {boolean} [rot=false]
     * @param {boolean} [allowRotation=false]
     * @memberof Rectangle
     */
    constructor(width = 0, height = 0, x = 0, y = 0, rot = false, allowRotation = undefined) {
        /**
         * Oversized tag on rectangle which is bigger than packer itself.
         *
         * @type {boolean}
         * @memberof Rectangle
         */
        this.oversized = false;
        this._rot = false;
        this._allowRotation = undefined;
        this._dirty = 0;
        this._width = width;
        this._height = height;
        this._x = x;
        this._y = y;
        this._data = {};
        this._rot = rot;
        this._allowRotation = allowRotation;
    }
    /**
     * Test if two given rectangle collide each other
     *
     * @static
     * @param {IRectangle} first
     * @param {IRectangle} second
     * @returns
     * @memberof Rectangle
     */
    static Collide(first, second) { return first.collide(second); }
    /**
     * Test if the first rectangle contains the second one
     *
     * @static
     * @param {IRectangle} first
     * @param {IRectangle} second
     * @returns
     * @memberof Rectangle
     */
    static Contain(first, second) { return first.contain(second); }
    /**
     * Get the area (w * h) of the rectangle
     *
     * @returns {number}
     * @memberof Rectangle
     */
    area() { return this.width * this.height; }
    /**
     * Test if the given rectangle collide with this rectangle.
     *
     * @param {IRectangle} rect
     * @returns {boolean}
     * @memberof Rectangle
     */
    collide(rect) {
        return (rect.x < this.x + this.width &&
            rect.x + rect.width > this.x &&
            rect.y < this.y + this.height &&
            rect.y + rect.height > this.y);
    }
    /**
     * Test if this rectangle contains the given rectangle.
     *
     * @param {IRectangle} rect
     * @returns {boolean}
     * @memberof Rectangle
     */
    contain(rect) {
        return (rect.x >= this.x && rect.y >= this.y &&
            rect.x + rect.width <= this.x + this.width && rect.y + rect.height <= this.y + this.height);
    }
    get width() { return this._width; }
    set width(value) {
        if (value === this._width)
            return;
        this._width = value;
        this._dirty++;
    }
    get height() { return this._height; }
    set height(value) {
        if (value === this._height)
            return;
        this._height = value;
        this._dirty++;
    }
    get x() { return this._x; }
    set x(value) {
        if (value === this._x)
            return;
        this._x = value;
        this._dirty++;
    }
    get y() { return this._y; }
    set y(value) {
        if (value === this._y)
            return;
        this._y = value;
        this._dirty++;
    }
    /**
     * If the rectangle is rotated
     *
     * @type {boolean}
     * @memberof Rectangle
     */
    get rot() { return this._rot; }
    /**
     * Set the rotate tag of the rectangle.
     *
     * note: after `rot` is set, `width/height` of this rectangle is swaped.
     *
     * @memberof Rectangle
     */
    set rot(value) {
        if (this._allowRotation === false)
            return;
        if (this._rot !== value) {
            const tmp = this.width;
            this.width = this.height;
            this.height = tmp;
            this._rot = value;
            this._dirty++;
        }
    }
    /**
     * If the rectangle allow rotation
     *
     * @type {boolean}
     * @memberof Rectangle
     */
    get allowRotation() { return this._allowRotation; }
    /**
     * Set the allowRotation tag of the rectangle.
     *
     * @memberof Rectangle
     */
    set allowRotation(value) {
        if (this._allowRotation !== value) {
            this._allowRotation = value;
            this._dirty++;
        }
    }
    get data() { return this._data; }
    set data(value) {
        if (value === null || value === this._data)
            return;
        this._data = value;
        // extract allowRotation settings
        if (typeof value === "object" && value.hasOwnProperty("allowRotation")) {
            this._allowRotation = value.allowRotation;
        }
        this._dirty++;
    }
    get dirty() { return this._dirty > 0; }
    setDirty(value = true) { this._dirty = value ? this._dirty + 1 : 0; }
}

const EDGE_MAX_VALUE = 4096;
var PACKING_LOGIC;
(function (PACKING_LOGIC) {
    PACKING_LOGIC[PACKING_LOGIC["MAX_AREA"] = 0] = "MAX_AREA";
    PACKING_LOGIC[PACKING_LOGIC["MAX_EDGE"] = 1] = "MAX_EDGE";
})(PACKING_LOGIC || (PACKING_LOGIC = {}));
let Bin$1 = class Bin {
    constructor() {
        this._dirty = 0;
    }
    get dirty() { return this._dirty > 0 || this.rects.some(rect => rect.dirty); }
    /**
     * Set bin dirty status
     *
     * @memberof Bin
     */
    setDirty(value = true) {
        this._dirty = value ? this._dirty + 1 : 0;
        if (!value) {
            for (let rect of this.rects) {
                if (rect.setDirty)
                    rect.setDirty(false);
            }
        }
    }
};

class MaxRectsBin extends Bin$1 {
    constructor(maxWidth = EDGE_MAX_VALUE, maxHeight = EDGE_MAX_VALUE, padding = 0, options = {}) {
        super();
        this.maxWidth = maxWidth;
        this.maxHeight = maxHeight;
        this.padding = padding;
        this.freeRects = [];
        this.rects = [];
        this.verticalExpand = false;
        this.options = {
            smart: true,
            pot: true,
            square: true,
            allowRotation: false,
            tag: false,
            exclusiveTag: true,
            border: 0,
            logic: PACKING_LOGIC.MAX_EDGE
        };
        this.options = Object.assign(Object.assign({}, this.options), options);
        this.width = this.options.smart ? 0 : maxWidth;
        this.height = this.options.smart ? 0 : maxHeight;
        this.border = this.options.border ? this.options.border : 0;
        this.freeRects.push(new Rectangle(this.maxWidth + this.padding - this.border * 2, this.maxHeight + this.padding - this.border * 2, this.border, this.border));
        this.stage = new Rectangle(this.width, this.height);
    }
    add(...args) {
        let data;
        let rect;
        if (args.length === 1) {
            if (typeof args[0] !== 'object')
                throw new Error("MacrectsBin.add(): Wrong parameters");
            rect = args[0];
            // Check if rect.tag match bin.tag, if bin.tag not defined, it will accept any rect
            let tag = (rect.data && rect.data.tag) ? rect.data.tag : rect.tag ? rect.tag : undefined;
            if (this.options.tag && this.options.exclusiveTag && this.tag !== tag)
                return undefined;
        }
        else {
            data = args.length > 2 ? args[2] : null;
            // Check if data.tag match bin.tag, if bin.tag not defined, it will accept any rect
            if (this.options.tag && this.options.exclusiveTag) {
                if (data && this.tag !== data.tag)
                    return undefined;
                if (!data && this.tag)
                    return undefined;
            }
            rect = new Rectangle(args[0], args[1]);
            rect.data = data;
            rect.setDirty(false);
        }
        const result = this.place(rect);
        if (result)
            this.rects.push(result);
        return result;
    }
    repack() {
        let unpacked = [];
        this.reset();
        // re-sort rects from big to small
        this.rects.sort((a, b) => {
            const result = Math.max(b.width, b.height) - Math.max(a.width, a.height);
            if (result === 0 && a.hash && b.hash) {
                return a.hash > b.hash ? -1 : 1;
            }
            else
                return result;
        });
        for (let rect of this.rects) {
            if (!this.place(rect)) {
                unpacked.push(rect);
            }
        }
        for (let rect of unpacked)
            this.rects.splice(this.rects.indexOf(rect), 1);
        return unpacked.length > 0 ? unpacked : undefined;
    }
    reset(deepReset = false, resetOption = false) {
        if (deepReset) {
            if (this.data)
                delete this.data;
            if (this.tag)
                delete this.tag;
            this.rects = [];
            if (resetOption) {
                this.options = {
                    smart: true,
                    pot: true,
                    square: true,
                    allowRotation: false,
                    tag: false,
                    border: 0
                };
            }
        }
        this.width = this.options.smart ? 0 : this.maxWidth;
        this.height = this.options.smart ? 0 : this.maxHeight;
        this.border = this.options.border ? this.options.border : 0;
        this.freeRects = [new Rectangle(this.maxWidth + this.padding - this.border * 2, this.maxHeight + this.padding - this.border * 2, this.border, this.border)];
        this.stage = new Rectangle(this.width, this.height);
        this._dirty = 0;
    }
    clone() {
        let clonedBin = new MaxRectsBin(this.maxWidth, this.maxHeight, this.padding, this.options);
        for (let rect of this.rects) {
            clonedBin.add(rect);
        }
        return clonedBin;
    }
    place(rect) {
        // recheck if tag matched
        let tag = (rect.data && rect.data.tag) ? rect.data.tag : rect.tag ? rect.tag : undefined;
        if (this.options.tag && this.options.exclusiveTag && this.tag !== tag)
            return undefined;
        let node;
        let allowRotation;
        // getter/setter do not support hasOwnProperty()
        if (rect.hasOwnProperty("_allowRotation") && rect.allowRotation !== undefined) {
            allowRotation = rect.allowRotation; // Per Rectangle allowRotation override packer settings
        }
        else {
            allowRotation = this.options.allowRotation;
        }
        node = this.findNode(rect.width + this.padding, rect.height + this.padding, allowRotation);
        if (node) {
            this.updateBinSize(node);
            let numRectToProcess = this.freeRects.length;
            let i = 0;
            while (i < numRectToProcess) {
                if (this.splitNode(this.freeRects[i], node)) {
                    this.freeRects.splice(i, 1);
                    numRectToProcess--;
                    i--;
                }
                i++;
            }
            this.pruneFreeList();
            this.verticalExpand = this.width > this.height ? true : false;
            rect.x = node.x;
            rect.y = node.y;
            if (rect.rot === undefined)
                rect.rot = false;
            rect.rot = node.rot ? !rect.rot : rect.rot;
            this._dirty++;
            return rect;
        }
        else if (!this.verticalExpand) {
            if (this.updateBinSize(new Rectangle(rect.width + this.padding, rect.height + this.padding, this.width + this.padding - this.border, this.border)) || this.updateBinSize(new Rectangle(rect.width + this.padding, rect.height + this.padding, this.border, this.height + this.padding - this.border))) {
                return this.place(rect);
            }
        }
        else {
            if (this.updateBinSize(new Rectangle(rect.width + this.padding, rect.height + this.padding, this.border, this.height + this.padding - this.border)) || this.updateBinSize(new Rectangle(rect.width + this.padding, rect.height + this.padding, this.width + this.padding - this.border, this.border))) {
                return this.place(rect);
            }
        }
        return undefined;
    }
    findNode(width, height, allowRotation) {
        let score = Number.MAX_VALUE;
        let areaFit;
        let r;
        let bestNode;
        for (let i in this.freeRects) {
            r = this.freeRects[i];
            if (r.width >= width && r.height >= height) {
                areaFit = (this.options.logic === PACKING_LOGIC.MAX_AREA) ?
                    r.width * r.height - width * height :
                    Math.min(r.width - width, r.height - height);
                if (areaFit < score) {
                    bestNode = new Rectangle(width, height, r.x, r.y);
                    score = areaFit;
                }
            }
            if (!allowRotation)
                continue;
            // Continue to test 90-degree rotated rectangle
            if (r.width >= height && r.height >= width) {
                areaFit = (this.options.logic === PACKING_LOGIC.MAX_AREA) ?
                    r.width * r.height - height * width :
                    Math.min(r.height - width, r.width - height);
                if (areaFit < score) {
                    bestNode = new Rectangle(height, width, r.x, r.y, true); // Rotated node
                    score = areaFit;
                }
            }
        }
        return bestNode;
    }
    splitNode(freeRect, usedNode) {
        // Test if usedNode intersect with freeRect
        if (!freeRect.collide(usedNode))
            return false;
        // Do vertical split
        if (usedNode.x < freeRect.x + freeRect.width && usedNode.x + usedNode.width > freeRect.x) {
            // New node at the top side of the used node
            if (usedNode.y > freeRect.y && usedNode.y < freeRect.y + freeRect.height) {
                let newNode = new Rectangle(freeRect.width, usedNode.y - freeRect.y, freeRect.x, freeRect.y);
                this.freeRects.push(newNode);
            }
            // New node at the bottom side of the used node
            if (usedNode.y + usedNode.height < freeRect.y + freeRect.height) {
                let newNode = new Rectangle(freeRect.width, freeRect.y + freeRect.height - (usedNode.y + usedNode.height), freeRect.x, usedNode.y + usedNode.height);
                this.freeRects.push(newNode);
            }
        }
        // Do Horizontal split
        if (usedNode.y < freeRect.y + freeRect.height &&
            usedNode.y + usedNode.height > freeRect.y) {
            // New node at the left side of the used node.
            if (usedNode.x > freeRect.x && usedNode.x < freeRect.x + freeRect.width) {
                let newNode = new Rectangle(usedNode.x - freeRect.x, freeRect.height, freeRect.x, freeRect.y);
                this.freeRects.push(newNode);
            }
            // New node at the right side of the used node.
            if (usedNode.x + usedNode.width < freeRect.x + freeRect.width) {
                let newNode = new Rectangle(freeRect.x + freeRect.width - (usedNode.x + usedNode.width), freeRect.height, usedNode.x + usedNode.width, freeRect.y);
                this.freeRects.push(newNode);
            }
        }
        return true;
    }
    pruneFreeList() {
        // Go through each pair of freeRects and remove any rects that is redundant
        let i = 0;
        let j = 0;
        let len = this.freeRects.length;
        while (i < len) {
            j = i + 1;
            let tmpRect1 = this.freeRects[i];
            while (j < len) {
                let tmpRect2 = this.freeRects[j];
                if (tmpRect2.contain(tmpRect1)) {
                    this.freeRects.splice(i, 1);
                    i--;
                    len--;
                    break;
                }
                if (tmpRect1.contain(tmpRect2)) {
                    this.freeRects.splice(j, 1);
                    j--;
                    len--;
                }
                j++;
            }
            i++;
        }
    }
    updateBinSize(node) {
        if (!this.options.smart)
            return false;
        if (this.stage.contain(node))
            return false;
        let tmpWidth = Math.max(this.width, node.x + node.width - this.padding + this.border);
        let tmpHeight = Math.max(this.height, node.y + node.height - this.padding + this.border);
        if (this.options.allowRotation) {
            // do extra test on rotated node whether it's a better choice
            const rotWidth = Math.max(this.width, node.x + node.height - this.padding + this.border);
            const rotHeight = Math.max(this.height, node.y + node.width - this.padding + this.border);
            if (rotWidth * rotHeight < tmpWidth * tmpHeight) {
                tmpWidth = rotWidth;
                tmpHeight = rotHeight;
            }
        }
        if (this.options.pot) {
            tmpWidth = Math.pow(2, Math.ceil(Math.log(tmpWidth) * Math.LOG2E));
            tmpHeight = Math.pow(2, Math.ceil(Math.log(tmpHeight) * Math.LOG2E));
        }
        if (this.options.square) {
            tmpWidth = tmpHeight = Math.max(tmpWidth, tmpHeight);
        }
        if (tmpWidth > this.maxWidth + this.padding || tmpHeight > this.maxHeight + this.padding) {
            return false;
        }
        this.expandFreeRects(tmpWidth + this.padding, tmpHeight + this.padding);
        this.width = this.stage.width = tmpWidth;
        this.height = this.stage.height = tmpHeight;
        return true;
    }
    expandFreeRects(width, height) {
        this.freeRects.forEach((freeRect, index) => {
            if (freeRect.x + freeRect.width >= Math.min(this.width + this.padding - this.border, width)) {
                freeRect.width = width - freeRect.x - this.border;
            }
            if (freeRect.y + freeRect.height >= Math.min(this.height + this.padding - this.border, height)) {
                freeRect.height = height - freeRect.y - this.border;
            }
        }, this);
        this.freeRects.push(new Rectangle(width - this.width - this.padding, height - this.border * 2, this.width + this.padding - this.border, this.border));
        this.freeRects.push(new Rectangle(width - this.border * 2, height - this.height - this.padding, this.border, this.height + this.padding - this.border));
        this.freeRects = this.freeRects.filter(freeRect => {
            return !(freeRect.width <= 0 || freeRect.height <= 0 || freeRect.x < this.border || freeRect.y < this.border);
        });
        this.pruneFreeList();
    }
}

class OversizedElementBin extends Bin$1 {
    constructor(...args) {
        super();
        this.rects = [];
        if (args.length === 1) {
            if (typeof args[0] !== 'object')
                throw new Error("OversizedElementBin: Wrong parameters");
            const rect = args[0];
            this.rects = [rect];
            this.width = rect.width;
            this.height = rect.height;
            this.data = rect.data;
            rect.oversized = true;
        }
        else {
            this.width = args[0];
            this.height = args[1];
            this.data = args.length > 2 ? args[2] : null;
            const rect = new Rectangle(this.width, this.height);
            rect.oversized = true;
            rect.data = this.data;
            this.rects.push(rect);
        }
        this.freeRects = [];
        this.maxWidth = this.width;
        this.maxHeight = this.height;
        this.options = { smart: false, pot: false, square: false };
    }
    add() { return undefined; }
    reset(deepReset = false) {
        // nothing to do here
    }
    repack() { return undefined; }
    clone() {
        let clonedBin = new OversizedElementBin(this.rects[0]);
        return clonedBin;
    }
}

class MaxRectsPacker {
    /**
     * Creates an instance of MaxRectsPacker.
     *
     * @param {number} width of the output atlas (default is 4096)
     * @param {number} height of the output atlas (default is 4096)
     * @param {number} padding between glyphs/images (default is 0)
     * @param {IOption} [options={}] (Optional) packing options
     * @memberof MaxRectsPacker
     */
    constructor(width = EDGE_MAX_VALUE, height = EDGE_MAX_VALUE, padding = 0, options = {}) {
        this.width = width;
        this.height = height;
        this.padding = padding;
        /**
         * Options for MaxRect Packer
         *
         * @property {boolean} options.smart Smart sizing packer (default is true)
         * @property {boolean} options.pot use power of 2 sizing (default is true)
         * @property {boolean} options.square use square size (default is false)
         * @property {boolean} options.allowRotation allow rotation packing (default is false)
         * @property {boolean} options.tag allow auto grouping based on `rect.tag` (default is false)
         * @property {boolean} options.exclusiveTag tagged rects will have dependent bin, if set to `false`, packer will try to put tag rects into the same bin (default is true)
         * @property {boolean} options.border atlas edge spacing (default is 0)
         * @property {PACKING_LOGIC} options.logic MAX_AREA or MAX_EDGE based sorting logic (default is MAX_EDGE)
         * @export
         * @interface Option
         */
        this.options = {
            smart: true,
            pot: true,
            square: false,
            allowRotation: false,
            tag: false,
            exclusiveTag: true,
            border: 0,
            logic: PACKING_LOGIC.MAX_EDGE
        };
        this._currentBinIndex = 0;
        this.bins = [];
        this.options = Object.assign(Object.assign({}, this.options), options);
    }
    add(...args) {
        if (args.length === 1) {
            if (typeof args[0] !== 'object')
                throw new Error("MacrectsPacker.add(): Wrong parameters");
            const rect = args[0];
            if (rect.width > this.width || rect.height > this.height) {
                this.bins.push(new OversizedElementBin(rect));
            }
            else {
                let added = this.bins.slice(this._currentBinIndex).find(bin => bin.add(rect) !== undefined);
                if (!added) {
                    let bin = new MaxRectsBin(this.width, this.height, this.padding, this.options);
                    let tag = (rect.data && rect.data.tag) ? rect.data.tag : rect.tag ? rect.tag : undefined;
                    if (this.options.tag && tag)
                        bin.tag = tag;
                    bin.add(rect);
                    this.bins.push(bin);
                }
            }
            return rect;
        }
        else {
            const rect = new Rectangle(args[0], args[1]);
            if (args.length > 2)
                rect.data = args[2];
            if (rect.width > this.width || rect.height > this.height) {
                this.bins.push(new OversizedElementBin(rect));
            }
            else {
                let added = this.bins.slice(this._currentBinIndex).find(bin => bin.add(rect) !== undefined);
                if (!added) {
                    let bin = new MaxRectsBin(this.width, this.height, this.padding, this.options);
                    if (this.options.tag && rect.data.tag)
                        bin.tag = rect.data.tag;
                    bin.add(rect);
                    this.bins.push(bin);
                }
            }
            return rect;
        }
    }
    /**
     * Add an Array of bins/rectangles to the packer.
     *
     * `Javascript`: Any object has property: { width, height, ... } is accepted.
     *
     * `Typescript`: object shall extends `MaxrectsPacker.IRectangle`.
     *
     * note: object has `hash` property will have more stable packing result
     *
     * @param {IRectangle[]} rects Array of bin/rectangles
     * @memberof MaxRectsPacker
     */
    addArray(rects) {
        if (!this.options.tag || this.options.exclusiveTag) {
            // if not using tag or using exclusiveTag, old approach
            this.sort(rects, this.options.logic).forEach(rect => this.add(rect));
        }
        else {
            // sort rects by tags first
            if (rects.length === 0)
                return;
            rects.sort((a, b) => {
                const aTag = (a.data && a.data.tag) ? a.data.tag : a.tag ? a.tag : undefined;
                const bTag = (b.data && b.data.tag) ? b.data.tag : b.tag ? b.tag : undefined;
                return bTag === undefined ? -1 : aTag === undefined ? 1 : bTag > aTag ? -1 : 1;
            });
            // iterate all bins to find the first bin which can place rects with same tag
            //
            let currentTag;
            let currentIdx = 0;
            let targetBin = this.bins.slice(this._currentBinIndex).find((bin, binIndex) => {
                let testBin = bin.clone();
                for (let i = currentIdx; i < rects.length; i++) {
                    const rect = rects[i];
                    const tag = (rect.data && rect.data.tag) ? rect.data.tag : rect.tag ? rect.tag : undefined;
                    // initialize currentTag
                    if (i === 0)
                        currentTag = tag;
                    if (tag !== currentTag) {
                        // all current tag memeber tested successfully
                        currentTag = tag;
                        // do addArray()
                        this.sort(rects.slice(currentIdx, i), this.options.logic).forEach(r => bin.add(r));
                        currentIdx = i;
                        // recrusively addArray() with remaining rects
                        this.addArray(rects.slice(i));
                        return true;
                    }
                    // remaining untagged rect will use normal addArray()
                    if (tag === undefined) {
                        // do addArray()
                        this.sort(rects.slice(i), this.options.logic).forEach(r => this.add(r));
                        currentIdx = rects.length;
                        // end test
                        return true;
                    }
                    // still in the same tag group
                    if (testBin.add(rect) === undefined) {
                        // add the rects that could fit into the bins already
                        // do addArray()
                        this.sort(rects.slice(currentIdx, i), this.options.logic).forEach(r => bin.add(r));
                        currentIdx = i;
                        // current bin cannot contain all tag members
                        // procceed to test next bin
                        return false;
                    }
                }
                // all rects tested
                // do addArray() to the remaining tag group
                this.sort(rects.slice(currentIdx), this.options.logic).forEach(r => bin.add(r));
                return true;
            });
            // create a new bin if no current bin fit
            if (!targetBin) {
                const rect = rects[currentIdx];
                const bin = new MaxRectsBin(this.width, this.height, this.padding, this.options);
                const tag = (rect.data && rect.data.tag) ? rect.data.tag : rect.tag ? rect.tag : undefined;
                if (this.options.tag && this.options.exclusiveTag && tag)
                    bin.tag = tag;
                this.bins.push(bin);
                // Add the rect to the newly created bin
                bin.add(rect);
                currentIdx++;
                this.addArray(rects.slice(currentIdx));
            }
        }
    }
    /**
     * Reset entire packer to initial states, keep settings
     *
     * @memberof MaxRectsPacker
     */
    reset() {
        this.bins = [];
        this._currentBinIndex = 0;
    }
    /**
     * Repack all elements inside bins
     *
     * @param {boolean} [quick=true] quick repack only dirty bins
     * @returns {void}
     * @memberof MaxRectsPacker
     */
    repack(quick = true) {
        if (quick) {
            let unpack = [];
            for (let bin of this.bins) {
                if (bin.dirty) {
                    let up = bin.repack();
                    if (up)
                        unpack.push(...up);
                }
            }
            this.addArray(unpack);
            return;
        }
        if (!this.dirty)
            return;
        const allRects = this.rects;
        this.reset();
        this.addArray(allRects);
    }
    /**
     * Stop adding new element to the current bin and return a new bin.
     *
     * note: After calling `next()` all elements will no longer added to previous bins.
     *
     * @returns {Bin}
     * @memberof MaxRectsPacker
     */
    next() {
        this._currentBinIndex = this.bins.length;
        return this._currentBinIndex;
    }
    /**
     * Load bins to the packer, overwrite exist bins
     *
     * @param {MaxRectsBin[]} bins MaxRectsBin objects
     * @memberof MaxRectsPacker
     */
    load(bins) {
        bins.forEach((bin, index) => {
            if (bin.maxWidth > this.width || bin.maxHeight > this.height) {
                this.bins.push(new OversizedElementBin(bin.width, bin.height, {}));
            }
            else {
                let newBin = new MaxRectsBin(this.width, this.height, this.padding, bin.options);
                newBin.freeRects.splice(0);
                bin.freeRects.forEach((r, i) => {
                    newBin.freeRects.push(new Rectangle(r.width, r.height, r.x, r.y));
                });
                newBin.width = bin.width;
                newBin.height = bin.height;
                if (bin.tag)
                    newBin.tag = bin.tag;
                this.bins[index] = newBin;
            }
        }, this);
    }
    /**
     * Output current bins to save
     *
     * @memberof MaxRectsPacker
     */
    save() {
        let saveBins = [];
        this.bins.forEach((bin => {
            let saveBin = {
                width: bin.width,
                height: bin.height,
                maxWidth: bin.maxWidth,
                maxHeight: bin.maxHeight,
                freeRects: [],
                rects: [],
                options: bin.options
            };
            if (bin.tag)
                saveBin = Object.assign(Object.assign({}, saveBin), { tag: bin.tag });
            bin.freeRects.forEach(r => {
                saveBin.freeRects.push({
                    x: r.x,
                    y: r.y,
                    width: r.width,
                    height: r.height
                });
            });
            saveBins.push(saveBin);
        }));
        return saveBins;
    }
    /**
     * Sort the given rects based on longest edge or surface area.
     *
     * If rects have the same sort value, will sort by second key `hash` if presented.
     *
     * @private
     * @param {T[]} rects
     * @param {PACKING_LOGIC} [logic=PACKING_LOGIC.MAX_EDGE] sorting logic, "area" or "edge"
     * @returns
     * @memberof MaxRectsPacker
     */
    sort(rects, logic = PACKING_LOGIC.MAX_EDGE) {
        return rects.slice().sort((a, b) => {
            const result = (logic === PACKING_LOGIC.MAX_EDGE) ?
                Math.max(b.width, b.height) - Math.max(a.width, a.height) :
                b.width * b.height - a.width * a.height;
            if (result === 0 && a.hash && b.hash) {
                return a.hash > b.hash ? -1 : 1;
            }
            else
                return result;
        });
    }
    /**
     * Return current functioning bin index, perior to this wont accept any new elements
     *
     * @readonly
     * @type {number}
     * @memberof MaxRectsPacker
     */
    get currentBinIndex() { return this._currentBinIndex; }
    /**
     * Returns dirty status of all child bins
     *
     * @readonly
     * @type {boolean}
     * @memberof MaxRectsPacker
     */
    get dirty() { return this.bins.some(bin => bin.dirty); }
    /**
     * Return all rectangles in this packer
     *
     * @readonly
     * @type {T[]}
     * @memberof MaxRectsPacker
     */
    get rects() {
        let allRects = [];
        for (let bin of this.bins) {
            allRects.push(...bin.rects);
        }
        return allRects;
    }
}

var __awaiter$5 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class TTImgData {
    constructor() {
        this.borderX1 = 0;
        this.borderY1 = 0;
        this.borderX2 = 0;
        this.borderY2 = 0;
    }
}
//Target2D是对ImageBitmap的封装，由于他的设计有点2b，所以封装一下
class Target2D {
    constructor(width, height) {
        this._canvas = new OffscreenCanvas(256, 256);
        this._canvas = new OffscreenCanvas(width, height);
        this._r2d = this._canvas.getContext("2d", { willReadFrequently: true });
        this._canvas.transferToImageBitmap();
        this._r2d.imageSmoothingEnabled = false;
    }
    getWidth() {
        return this._canvas.width;
    }
    getHeight() {
        return this._canvas.height;
    }
    setWidth(width) {
        this._canvas.width = width;
    }
    setHeight(height) {
        this._canvas.height = height;
    }
    getContext() {
        return this._r2d;
    }
    getCanvas() {
        return this._canvas;
    }
    getBitmap() {
        return this.bitmap;
    }
    //每次UpdateBitmap之后，应该要引发重绘
    updateBitmap() {
        // if (renderFunc != null)
        //     renderFunc();
        if (this.bitmap = null)
            this.bitmap.close(); //先灭掉上一个bitmap
        this.bitmap = this._canvas.transferToImageBitmap();
    }
}
//一个绘图区域
class DrawArea extends Target2D {
    Resize_Scale(neww, newh, linear) {
        if (neww == this.getWidth() && newh == this.getHeight()) {
            return;
        }
        //方案1，硬算像素
        let sw = this.getWidth();
        let sh = this.getHeight();
        // let olddata = this.getContext().getImageData(0, 0, sw, sh);
        // this.setWidth(neww);
        // this.setHeight(newh);
        // let newdata = new ImageData(neww, newh);
        // let xs = sw / neww;
        // let ys = sh / newh;
        // for (var j = 0; j < newh; j++) {
        //     for (var i = 0; i < neww; i++) {
        //         let srcx = (i * xs) | 0;
        //         let srcy = (j * ys) | 0;
        //         let srci = (srcy * sw + srcx) * 4;
        //         let newi = (j * neww + i) * 4;
        //         newdata.data[newi + 0] = olddata.data[srci + 0];
        //         newdata.data[newi + 1] = olddata.data[srci + 1];
        //         newdata.data[newi + 2] = olddata.data[srci + 2];
        //         newdata.data[newi + 3] = olddata.data[srci + 3];
        //     }
        // }
        // this.getContext().putImageData(newdata, 0, 0);
        //方案2，画一遍不就完了
        this.setWidth(neww);
        this.setHeight(newh);
        this._r2d.imageSmoothingEnabled = linear;
        this._r2d.drawImage(this.bitmap, 0, 0, sw, sh, 0, 0, neww, newh);
        this._r2d.imageSmoothingEnabled = false;
        this.updateBitmap();
    }
    Resize_Cut(neww, newh, dirx, diry) {
        if (neww == this.getWidth() && newh == this.getHeight()) {
            return;
        }
        let sw = this.getWidth();
        let sh = this.getHeight();
        this.setWidth(neww);
        this.setHeight(newh);
        let x = 0;
        let y = 0;
        if (dirx == -1) {
            x = 0;
        }
        else if (dirx == 0) {
            x = ((neww - sw) / 2) | 0;
        }
        else if (dirx == 1) {
            x = (neww - sw);
        }
        if (diry == -1) {
            y = 0;
        }
        else if (diry == 0) {
            y = ((newh - sh) / 2) | 0;
        }
        else if (diry == 1) {
            y = (newh - sh);
        }
        this._r2d.drawImage(this.bitmap, x, y);
        this.updateBitmap();
    }
    DrawArea_Init(img) {
        this.setWidth(img.width);
        this.setHeight(img.height);
        this._r2d.drawImage(img, 0, 0);
        this.updateBitmap();
    }
    updateBitmap() {
        super.updateBitmap();
        this._r2d.drawImage(this.bitmap, 0, 0);
    }
    UpdateSubArea(imgdata, x, y) {
        if (this.bitmap != null) {
            this._r2d.drawImage(this.bitmap, 0, 0);
        }
        this._r2d.putImageData(imgdata, x, y);
        this.updateBitmap();
    }
    ClearColor(color) {
        //this._r2d.beginPath();
        this._r2d.fillStyle = color.toString();
        this._r2d.fillRect(0, 0, this.getWidth(), this.getHeight());
        //this._r2d.closePath();
    }
    ClearRect(x, y, w, h) {
        this._r2d.clearRect(x, y, w, h);
    }
    DrawRect(x, y, w, h, color) {
        // if (color.A < 16) {
        //     this._r2d.globalAlpha = 1.0;
        //     this._r2d.save();
        //     this._r2d.beginPath();
        //     this._r2d.fillStyle = color.toString();
        //     this._r2d.lineWidth = 1;
        //     this._r2d.rect(x, y, 5, 5);
        //     this._r2d.closePath();
        //     this._r2d.clip();
        //     this._r2d.clearRect(x, y, 5, 5);
        //     this._r2d.restore();
        //     return;
        // }
        //this._r2d.beginPath();
        this._r2d.fillStyle = color.toString();
        this._r2d.lineWidth = 1;
        this._r2d.fillRect(x, y, w, h);
        //this._r2d.closePath();
    }
}
class ImgTool {
    static Bin2Url(bin) {
        let blob = new Blob([bin]);
        return URL.createObjectURL(blob);
    }
    static Url2ImgAsync(url) {
        return new Promise((resolve, reject) => {
            let img = document.createElement("img");
            img.src = url;
            img.onload = () => {
                resolve(img);
            };
            img.onerror = () => {
                reject("img load fail.");
            };
        });
    }
    static Bin2ImgAsync(bin) {
        return __awaiter$5(this, void 0, void 0, function* () {
            let img = yield this.Url2ImgAsync(this.Bin2Url(bin));
            return img;
        });
    }
    static CreateImgData(width, height) {
        return this._backrender.getContext().createImageData(width, height);
    }
    static Bin2ImgDataAsync(bin) {
        return __awaiter$5(this, void 0, void 0, function* () {
            let img = yield this.Bin2ImgAsync(bin);
            return this.Img2Data(img);
        });
    }
    static Img2Data(img) {
        this._backrender.setWidth(img.width);
        this._backrender.setHeight(img.height);
        this._backrender.getContext().drawImage(img, 0, 0);
        let imgdata = this._backrender.getContext().getImageData(0, 0, this._backrender.getWidth(), this._backrender.getHeight());
        return imgdata;
    }
    static Canvas2PngFileDataAsync() {
        return __awaiter$5(this, void 0, void 0, function* () {
            let b = yield this._backrender.getCanvas().convertToBlob({ "type": "image/png" });
            let ab = yield b.arrayBuffer();
            return new Uint8Array(ab);
        });
    }
    static ImgData2BlobAsync(data) {
        return __awaiter$5(this, void 0, void 0, function* () {
            this._backrender.setWidth(data.width);
            this._backrender.setHeight(data.height);
            this._backrender.getContext().putImageData(data, 0, 0);
            let b = yield this._backrender.getCanvas().convertToBlob({ "type": "image/png" });
            return b;
        });
    }
    static ImgData2PngFileDataAsync(data) {
        return __awaiter$5(this, void 0, void 0, function* () {
            this._backrender.setWidth(data.width);
            this._backrender.setHeight(data.height);
            this._backrender.getContext().putImageData(data, 0, 0);
            return yield this.Canvas2PngFileDataAsync();
        });
    }
    static PutToImgData(target, src, x, y) {
        return __awaiter$5(this, void 0, void 0, function* () {
            for (var j = 0; j < src.height; j++) {
                for (var i = 0; i < src.width; i++) {
                    var dx = i + x;
                    var dy = j + y;
                    if (dx < 0 || dx >= target.width)
                        continue;
                    if (dy < 0 || dy >= target.height)
                        continue;
                    var srci = (j * src.width + i) * 4;
                    var desti = (dy * target.width + dx) * 4;
                    target.data[desti + 0] = src.data[srci + 0];
                    target.data[desti + 1] = src.data[srci + 1];
                    target.data[desti + 2] = src.data[srci + 2];
                    target.data[desti + 3] = src.data[srci + 3];
                }
            }
        });
    }
    static ImgFill(src) {
        let img = new TTImgData();
        {
            img.width = src.width;
            img.height = src.height;
            img.data = new Uint8Array(src.width * src.height * 4);
            for (var i = 0; i < img.data.length; i++) {
                img.data[i] = src.data[i];
            }
        }
        return img;
    }
    static ImgCut(src) {
        let x1 = src.width;
        let x2 = 0;
        let y1 = src.width;
        let y2 = 0;
        for (var y = 0; y < src.height; y++) {
            for (var x = 0; x < src.width; x++) {
                let a = src.data[(y * src.width + x) * 4 + 3];
                if (a > 0) {
                    if (x < x1)
                        x1 = x;
                    if (y < y1)
                        y1 = y;
                    if (x > x2)
                        x2 = x;
                    if (y > y2)
                        y2 = y;
                }
            }
        }
        let img = new TTImgData();
        img.borderX1 = x1;
        img.borderY1 = y1;
        img.borderX2 = src.width - 1 - x2;
        img.borderY2 = src.height - 1 - y2;
        let width = img.width = x2 - x1 + 1;
        let height = img.height = y2 - y1 + 1;
        img.data = new Uint8Array(width * height * 4);
        for (var sy = 0; sy < height; sy++) {
            for (var sx = 0; sx < width; sx++) {
                let srcseek = ((sy + y1) * src.width + (sx + x1)) * 4;
                let destseek = (sy * width + sx) * 4;
                img.data[destseek + 0] = src.data[srcseek + 0];
                img.data[destseek + 1] = src.data[srcseek + 1];
                img.data[destseek + 2] = src.data[srcseek + 2];
                img.data[destseek + 3] = src.data[srcseek + 3];
            }
        }
        return img;
    }
    static Pack(width, height, border, rects) {
        let mr = new MaxRectsPacker(width, height, border);
        mr.addArray(rects);
        let bins = [];
        for (var i = 0; i < mr.bins.length; i++) {
            let bin = new Bin();
            for (var j = 0; j < mr.bins[i].rects.length; j++) {
                bin.rects.push(mr.bins[i].rects[j]);
            }
            bins.push(bin);
        }
        return bins;
    }
}
ImgTool._backrender = new Target2D(256, 256);
class Bin {
    constructor() {
        this.rects = [];
    }
}

class RectRange {
    constructor(x1, y1, x2, y2) {
        this.x1 = Math.min(x1, x2);
        this.y1 = Math.min(y1, y2);
        this.x2 = Math.max(x1, x2);
        this.y2 = Math.max(y1, y2);
    }
    Clone() {
        return new RectRange(this.x1, this.y1, this.x2, this.y2);
    }
}

class DrawTool {
    constructor(editor) {
        this.editor = editor;
    }
    OnToolMouseWheel(area, delatvalue) {
    }
    OnSet() {
        this.editor.toolbox_model.Hide();
        this.editor.toolbox_color.Show();
    }
    static DrawLine(c2d, x1, y1, x2, y2, color, width, scalew = 1, scaleh = 1) {
        c2d.fillStyle = color.toString();
        let dx = x2 - x1;
        let dy = y2 - y1;
        let adx = Math.abs(dx);
        let ady = Math.abs(dy);
        let sdx = Math.sign(dx);
        let sdy = Math.sign(dy);
        let r = adx / ady;
        if (adx > ady) {
            for (var i = 0; i < adx; i++) {
                c2d.fillRect(((x1 + i * sdx) | 0) * scalew, ((y1 + i * sdy / r) | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            }
        }
        else {
            for (var i = 0; i < ady; i++) {
                c2d.fillRect(((x1 + i * sdx * r) | 0) * scalew, ((y1 + i * sdy) | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            }
        }
        //for循环有点问题，临时实现，不深究
        c2d.fillRect(x2 * scalew, y2 * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
    }
    static DrawRect(c2d, x1, y1, x2, y2, color, width, scalew = 1, scaleh = 1) {
        c2d.fillStyle = color.toString();
        let xx1 = Math.min(x1, x2);
        let xx2 = Math.max(x1, x2);
        let yy1 = Math.min(y1, y2);
        let yy2 = Math.max(y1, y2);
        for (var x = xx1; x <= xx2; x++) {
            c2d.fillRect((x | 0) * scalew, (y1 | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            c2d.fillRect((x | 0) * scalew, (y2 | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
        }
        for (var y = yy1 + 1; y < yy2; y++) {
            c2d.fillRect((x1 | 0) * scalew, (y | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
            c2d.fillRect((x2 | 0) * scalew, (y | 0) * scaleh, (width * scalew) | 0, (width * scaleh) | 0);
        }
    }
    //这样搞，半径是 sqrt (dx*dx +dy*dy)
    //这个效果的产生是个意外，但是效果还不错
    // static DrawCircle(c2d: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, color: Color32, width: number, scalew: number = 1, scaleh: number = 1): void {
    //     let cx = (x1 + x2) / 2
    //     let cy = (y1 + y2) / 2
    //     let dx = Math.abs(x2 - x1) / 2
    //     let dy = Math.abs(y2 - y1) / 2
    //     let lastcx = 0;
    //     let lastcy = 0;
    //     //this.DrawRect(c2d, cx, cy, cx + dx, cy + dy, color, width, scalew, scaleh);
    //     for (var i = 0; i <= 100; i++) {
    //         let rad = i * Math.PI * 2 / 100;
    //         let cirx = (Math.cos(rad) * dx + Math.sin(rad) * dx) + cx;
    //         let ciry = (-Math.sin(rad) * dy + Math.cos(rad) * dy) + cy;
    //         // cirx*=sx;
    //         // ciry*=sy;
    //         if (i > 0) {
    //             this.DrawLine(c2d, lastcx | 0, lastcy | 0, cirx | 0, ciry | 0, color, width, scalew, scaleh);
    //         }
    //         lastcx = cirx;
    //         lastcy = ciry;
    //     }
    // }
    //画正圆
    static DrawCircle_Perfect(c2d, x1, y1, x2, y2, color, width, scalew = 1, scaleh = 1) {
        let cx = (x1 + x2) / 2;
        let cy = (y1 + y2) / 2;
        let dx = Math.abs(x2 - x1) / 2;
        let dy = Math.abs(y2 - y1) / 2;
        let r = Math.sqrt(dx * dx + dy * dy);
        let lastcx = 0;
        let lastcy = 0;
        //this.DrawRect(c2d, cx, cy, cx + dx, cy + dy, color, width, scalew, scaleh);
        for (var i = 0; i <= 100; i++) {
            let rad = i * Math.PI * 2 / 100;
            let cirx = (Math.cos(rad) * r) + cx;
            let ciry = (-Math.sin(rad) * r) + cy;
            // cirx*=sx;
            // ciry*=sy;
            if (i > 0) {
                this.DrawLine(c2d, lastcx | 0, lastcy | 0, cirx | 0, ciry | 0, color, width, scalew, scaleh);
            }
            lastcx = cirx;
            lastcy = ciry;
        }
    }
    static DrawCircle_InBox(c2d, x1, y1, x2, y2, color, width, scalew = 1, scaleh = 1) {
        let cx = ((x1 + x2) / 2) | 0;
        let cy = ((y1 + y2) / 2) | 0;
        let dx = Math.abs(x2 - x1) / 2;
        let dy = Math.abs(y2 - y1) / 2;
        let lastcx = 0;
        let lastcy = 0;
        //this.DrawRect(c2d, cx, cy, cx + dx, cy + dy, color, width, scalew, scaleh);
        for (var i = 0; i <= 100; i++) {
            let rad = i * Math.PI * 2 / 100;
            let sin = Math.sin(rad);
            let cos = Math.cos(rad);
            let cirx = (cos * dx) + cx;
            let ciry = (-sin * dy) + cy;
            // cirx*=sx;
            // ciry*=sy;
            if (i > 0) {
                this.DrawLine(c2d, lastcx | 0, lastcy | 0, cirx | 0, ciry | 0, color, width, scalew, scaleh);
            }
            lastcx = cirx;
            lastcy = ciry;
        }
    }
}
class Pencil_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.linewidth = 1;
    }
    SetLineWidth(width) {
        this.linewidth = width;
    }
    OnLeftDown(area, x, y, color) {
        this.x = x;
        this.y = y;
        // area.DrawRect(x | 0, y | 0, this.linewidth, this.linewidth, color);
        let _r2d = area.getContext();
        _r2d.fillStyle = color.toString();
        _r2d.fillRect(x, y, this.linewidth, this.linewidth);
        area.updateBitmap();
    }
    OnLeftMove(area, x, y, color) {
        let _r2d = area.getContext();
        DrawTool.DrawLine(_r2d, this.x, this.y, x, y, color, this.linewidth);
        this.x = x;
        this.y = y;
        area.updateBitmap();
    }
    OnLeftUp(area, x, y, color) {
        this.editor.history.TrySave("铅笔");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        priview.fillStyle = color.toString();
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff";
        }
        else {
            priview.strokeStyle = "#000";
        }
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
    }
}
class Earser_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.linewidth = 1;
    }
    SetLineWidth(width) {
        this.linewidth = width;
    }
    OnSet() {
    }
    OnLeftDown(area, x, y, color) {
        area.ClearRect(x | 0, y | 0, this.linewidth, this.linewidth);
        area.updateBitmap();
    }
    OnLeftMove(area, x, y, color) {
        area.ClearRect(x | 0, y | 0, this.linewidth, this.linewidth);
        area.updateBitmap();
    }
    OnLeftUp(area, x, y, color) {
        this.editor.history.TrySave("橡皮");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        priview.fillStyle = "#fff";
        priview.strokeStyle = "#000";
        //priview.beginPath();
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        // priview.closePath();
    }
}
class DrawLine_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.linewidth = 1;
    }
    SetLineWidth(width) {
        this.linewidth = width;
    }
    OnLeftDown(area, x, y, color) {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;
    }
    OnLeftMove(area, x, y, color) {
        this.nx = x;
        this.ny = y;
    }
    OnLeftUp(area, x, y, color) {
        this.press = false;
        let _r2d = area.getContext();
        DrawTool.DrawLine(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        _r2d.fillStyle = color.toString();
        area.updateBitmap();
        this.editor.history.TrySave("画线");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        if (this.press) {
            //画假线
            if (this.x != this.nx || this.y != this.ny) {
                priview.fillStyle = color.toString();
                let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
                if (g < 0.6) {
                    priview.strokeStyle = "#fff";
                }
                else {
                    priview.strokeStyle = "#000";
                }
                DrawTool.DrawLine(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
            }
        }
        { //画提示
            priview.fillStyle = color.toString();
            let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
            if (g < 0.6) {
                priview.strokeStyle = "#fff";
            }
            else {
                priview.strokeStyle = "#000";
            }
            x = (x - offx) | 0;
            y = (y - offy) | 0;
            priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
            priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        }
    }
}
class DrawRect_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.linewidth = 1;
    }
    SetLineWidth(width) {
        this.linewidth = width;
    }
    OnLeftDown(area, x, y, color) {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;
    }
    OnLeftMove(area, x, y, color) {
        this.nx = x;
        this.ny = y;
    }
    OnLeftUp(area, x, y, color) {
        this.press = false;
        let _r2d = area.getContext();
        DrawTool.DrawRect(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        _r2d.fillStyle = color.toString();
        area.updateBitmap();
        this.editor.history.TrySave("画矩形");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        if (this.press) {
            //画假线
            if (this.x != this.nx || this.y != this.ny) {
                priview.fillStyle = color.toString();
                let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
                if (g < 0.6) {
                    priview.strokeStyle = "#fff";
                }
                else {
                    priview.strokeStyle = "#000";
                }
                DrawTool.DrawRect(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
            }
        }
        { //画提示
            priview.fillStyle = color.toString();
            let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
            if (g < 0.6) {
                priview.strokeStyle = "#fff";
            }
            else {
                priview.strokeStyle = "#000";
            }
            x = (x - offx) | 0;
            y = (y - offy) | 0;
            priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
            priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        }
    }
}
class Pick_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.linewidth = 1;
    }
    SetLineWidth(width) {
        //this.linewidth = width;
    }
    OnLeftDown(area, x, y, color) {
        let data = area.getContext().getImageData(x, y, 1, 1);
        let c = new Color32(data.data[0], data.data[1], data.data[2], 255);
        this.editor.setDrawColor(c, true);
    }
    OnLeftMove(area, x, y, color) {
        let data = area.getContext().getImageData(x, y, 1, 1);
        let c = new Color32(data.data[0], data.data[1], data.data[2], 255);
        this.editor.setDrawColor(c, true);
    }
    OnLeftUp(area, x, y, color) {
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        priview.fillStyle = "#fff";
        priview.strokeStyle = "#000";
        //priview.beginPath();
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        // priview.closePath();
    }
}
class Fill_Tool extends DrawTool {
    constructor(editor, tranmode = false) {
        super(editor);
        this.linewidth = 1;
        this.tranmode = tranmode;
    }
    SetLineWidth(width) {
        //this.linewidth = width;
    }
    OnSet() {
        if (this.tranmode == false) {
            super.OnSet();
        }
    }
    Color2Data(data, x, y, c) {
        let seek = (y * data.width + x) * 4;
        data.data[seek + 0] = c.R;
        data.data[seek + 1] = c.G;
        data.data[seek + 2] = c.B;
        data.data[seek + 3] = c.A;
    }
    ColorFormData(data, x, y) {
        let seek = (y * data.width + x) * 4;
        return new Color32(data.data[seek + 0], data.data[seek + 1], data.data[seek + 2], data.data[seek + 3]);
    }
    OnLeftDown(area, x, y, color) {
        let data = area.getContext().getImageData(0, 0, area.getWidth(), area.getHeight());
        let w = area.getWidth();
        let h = area.getHeight();
        let fillc = this.ColorFormData(data, x, y);
        if (this.tranmode) {
            if (fillc.A == 0)
                return;
            color.R = 0;
            color.G = 0;
            color.B = 0;
            color.A = 0;
        }
        else {
            if (Color32.Equal(fillc, color)) { //启动色一样就不填充
                return;
            }
        }
        this.Color2Data(data, x, y, color);
        let nextpos = [];
        nextpos.push({ x: x, y: y });
        while (nextpos.length > 0) {
            let nnext = [];
            for (var i = 0; i < nextpos.length; i++) {
                let px = nextpos[i].x;
                let py = nextpos[i].y;
                if (px > 0) {
                    let c = this.ColorFormData(data, px - 1, py);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px - 1, py, color);
                        nnext.push({ x: px - 1, y: py });
                    }
                }
                if (px + 1 < w) {
                    let c = this.ColorFormData(data, px + 1, py);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px + 1, py, color);
                        nnext.push({ x: px + 1, y: py });
                    }
                }
                if (py > 0) {
                    let c = this.ColorFormData(data, px, py - 1);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px, py - 1, color);
                        nnext.push({ x: px, y: py - 1 });
                    }
                }
                if (py + 1 < h) {
                    let c = this.ColorFormData(data, px, py + 1);
                    if (Color32.Equal(c, fillc)) {
                        this.Color2Data(data, px, py + 1, color);
                        nnext.push({ x: px, y: py + 1 });
                    }
                }
            }
            nextpos = nnext;
        }
        area.getContext().putImageData(data, 0, 0);
        area.updateBitmap();
    }
    OnLeftMove(area, x, y, color) {
    }
    OnLeftUp(area, x, y, color) {
        this.editor.history.TrySave(this.tranmode ? "填充透明" : "填充");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        priview.fillStyle = color.toString();
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff";
        }
        else {
            priview.strokeStyle = "#000";
        }
        //priview.beginPath();
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        // priview.closePath();
    }
}
class Select_Tool extends DrawTool {
    constructor(editor) {
        super(editor);
        this.linewidth = 1;
        this.editor = editor;
    }
    SetLineWidth(width) {
        //this.linewidth = width;
    }
    OnSet() {
    }
    OnLeftDown(area, x, y, color) {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;
        area.Select_Cancel();
    }
    OnLeftMove(area, x, y, color) {
        this.nx = x;
        this.ny = y;
        if (this.x != this.nx || this.y != this.ny)
            area.Select(new RectRange(this.x, this.y, this.nx, this.ny));
        else
            area.Select_Cancel();
    }
    OnLeftUp(area, x, y, color) {
        this.press = false;
        if (this.x != this.nx || this.y != this.ny)
            area.Select(new RectRange(this.x, this.y, this.nx, this.ny));
        else
            area.Select_Cancel();
        this.editor.history.TrySave("选区变动");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        priview.fillStyle = "#fff";
        priview.strokeStyle = "#000";
        //priview.beginPath();
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
    }
}
class Move_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.scalev = 1.0;
        this.move = false;
        this.scale = false;
    }
    OnSet() {
        this.scalev = 1.0;
        this.move = false;
        this.scale = false;
        this.srcbitmap = null;
    }
    OnLeftDown(area, x, y, color) {
        if (this.scale) {
            //area.applySelectData();
            //this.srcbitmap = area.getBitmapSelect();
            this.scalev = 1.0;
            this.scale = false;
        }
        this.x = x;
        this.y = y;
        if (area.getSelect() == null) {
            area.Select(new RectRange(0, 0, area.getWidth() - 1, area.getHeight() - 1));
        }
        if (!this.move) {
            //area.applySelectData();
            //area.cutDataToSelect();
            //this.srcbitmap = area.getBitmapSelect();
            let s = area.getSelect();
            this.srcsel = new RectRange(s.x1, s.y1, s.x2, s.y2);
            this.move = true;
            this.sx = 0;
            this.sy = 0;
        }
        if (area.getBitmapSelect() == null) {
            area.cutDataToSelect();
        }
        if (!this.srcbitmap)
            this.srcbitmap = area.getBitmapSelect();
    }
    OnLeftMove(area, x, y, color) {
        area.Select_ImgClear();
        area.Select_ImgDrawImage(this.srcbitmap, this.sx + (x - this.x), this.sy + (y - this.y));
        let selcect = area.getSelect();
        let w = selcect.x2 - selcect.x1;
        let h = selcect.y2 - selcect.y1;
        selcect.x1 = this.srcsel.x1 + this.sx + (x - this.x);
        selcect.y1 = this.srcsel.y1 + this.sy + (y - this.y);
        selcect.x2 = selcect.x1 + w;
        selcect.y2 = selcect.y1 + h;
        this.editor.drawCanvas.RePaint();
    }
    OnLeftUp(area, x, y, color) {
        this.sx += x - this.x;
        this.sy += y - this.y;
        this.move = true;
        this.editor.history.TrySave("选区移动");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        priview.fillStyle = color.toString();
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff";
        }
        else {
            priview.strokeStyle = "#000";
        }
        //priview.beginPath();
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.fillRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
    }
    SetLineWidth(width) {
    }
    OnToolMouseWheel(area, delatvalue) {
        if (this.move) {
            //area.applySelectData();
            //this.srcbitmap = area.getBitmapSelect();
            this.move = false;
        }
        if (area.getSelect() == null) {
            area.Select(new RectRange(0, 0, area.getWidth() - 1, area.getHeight() - 1));
        }
        if (!this.scale) {
            let s = area.getSelect();
            this.srcsel = new RectRange(s.x1, s.y1, s.x2, s.y2);
            this.x = s.x2 - s.x1;
            this.y = s.y2 - s.y1;
            this.sx = (s.x2 + s.x1) / 2;
            this.sy = (s.y2 + s.y1) / 2;
            this.scale = true;
        }
        if (area.getBitmapSelect() == null) {
            area.cutDataToSelect();
        }
        if (this.srcbitmap == null)
            this.srcbitmap = area.getBitmapSelect();
        area.Select_ImgClear();
        if (delatvalue > 0)
            this.scalev *= 2;
        else
            this.scalev /= 2;
        if (this.scalev > 4)
            this.scalev = 4;
        if (this.scalev < 0.125)
            this.scalev = 0.125;
        area.Select_ImgDrawImageScale(this.srcbitmap, this.srcsel, this.scalev, this.scalev);
        let s = area.getSelect();
        let w = this.x;
        let h = this.y;
        let cx = this.sx;
        let cy = this.sy;
        s.x1 = (cx - (w / 2) * this.scalev) | 0;
        s.y1 = (cy - (h / 2) * this.scalev) | 0;
        s.x2 = (cx + (w / 2) * this.scalev) | 0;
        s.y2 = (cy + (h / 2) * this.scalev) | 0;
        // if (s.x1 < 0) {
        //     s.x1 = 0;
        // }
        // if (s.y1 < 0) {
        //     s.y1 = 0;
        // }
        // if (s.x2 >= area.getWidth())
        //     s.x2 = area.getWidth() - 1;
        // if (s.y2 >= area.getHeight())
        //     s.y2 = area.getHeight() - 1;
        this.editor.drawCanvas.RePaint();
    }
}
class Rotate_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.rotate = false;
        this.rotatevalue = 0;
    }
    OnSet() {
        this.rotatevalue = 0;
        this.rotate = false;
        this.srcbitmap = null;
    }
    OnLeftDown(area, x, y, color) {
        this.x = x;
        this.y = y;
        if (this.rotate == false) {
            //area.applySelectData();
            this.srcbitmap = area.getBitmapSelect();
        }
        // if (area.getBitmapSelect() != null) {
        //     area.applySelectData();
        // }
        if (area.getSelect() == null) {
            area.Select(new RectRange(0, 0, area.getWidth() - 1, area.getHeight() - 1));
        }
        this.sx = (area.getSelect().x1 + area.getSelect().x2) / 2;
        this.sy = (area.getSelect().y1 + area.getSelect().y2) / 2;
        //select区域没东西时，才copy
        if (area.getBitmapSelect() == null) {
            area.cutDataToSelect();
        }
        if (this.srcbitmap == null)
            this.srcbitmap = area.getBitmapSelect();
    }
    OnLeftMove(area, x, y, color) {
        area.Select_ImgClear();
        let a = ((x - this.x) + (y - this.y)) / 100 * Math.PI;
        let rotate = this.rotatevalue + a;
        //this.rotatevalue = Math.PI / 2;
        area.Select_ImgDrawImage(this.srcbitmap, -this.sx, -this.sy, this.sx, this.sy, rotate); //a) ;
        // let selcect = area.getSelect();
        // let w = selcect.x2 - selcect.x1;
        // let h = selcect.y2 - selcect.y1;
        // selcect.x1 = this.sx + (x - this.x);
        // selcect.y1 = this.sy + (y - this.y);
        // selcect.x2 = selcect.x1 + w;
        // selcect.y2 = selcect.y1 + h;
        this.editor.drawCanvas.RePaint();
        this.rotate = true;
    }
    OnLeftUp(area, x, y, color) {
        this.rotate = true;
        let a = ((x - this.x) + (y - this.y)) / 100 * Math.PI;
        this.rotatevalue += a;
        this.editor.history.TrySave("选区旋转");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        priview.fillStyle = color.toString();
        let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
        if (g < 0.6) {
            priview.strokeStyle = "#fff";
        }
        else {
            priview.strokeStyle = "#000";
        }
        //priview.beginPath();
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.fillRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
        priview.strokeRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
    }
    SetLineWidth(width) {
    }
}
var DrawCircle_Mode;
(function (DrawCircle_Mode) {
    DrawCircle_Mode[DrawCircle_Mode["Center"] = 0] = "Center";
    DrawCircle_Mode[DrawCircle_Mode["TwoPoint"] = 1] = "TwoPoint";
    DrawCircle_Mode[DrawCircle_Mode["OutRect"] = 2] = "OutRect";
})(DrawCircle_Mode || (DrawCircle_Mode = {}));
class DrawCircle_Tool extends DrawTool {
    constructor(editor, mode) {
        super(editor);
        this.linewidth = 1;
        this.mode = mode;
    }
    SetLineWidth(width) {
        this.linewidth = width;
    }
    OnLeftDown(area, x, y, color) {
        this.x = x;
        this.y = y;
        this.nx = x;
        this.ny = y;
        this.press = true;
    }
    OnLeftMove(area, x, y, color) {
        this.nx = x;
        this.ny = y;
    }
    OnLeftUp(area, x, y, color) {
        this.press = false;
        let _r2d = area.getContext();
        if (this.mode == DrawCircle_Mode.Center) {
            let x1 = this.x - (this.nx - this.x);
            let y1 = this.y - (this.ny - this.y);
            DrawTool.DrawCircle_Perfect(_r2d, x1, y1, this.nx, this.ny, color, this.linewidth);
        }
        else if (this.mode == DrawCircle_Mode.TwoPoint) {
            DrawTool.DrawCircle_Perfect(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        }
        else if (this.mode == DrawCircle_Mode.OutRect) {
            DrawTool.DrawCircle_InBox(_r2d, this.x, this.y, this.nx, this.ny, color, this.linewidth);
        }
        _r2d.fillStyle = color.toString();
        area.updateBitmap();
        this.editor.history.TrySave("画圆");
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        if (this.press) {
            //画假线
            if (this.x != this.nx || this.y != this.ny) {
                priview.fillStyle = color.toString();
                let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
                if (g < 0.6) {
                    priview.strokeStyle = "#fff";
                }
                else {
                    priview.strokeStyle = "#000";
                }
                if (this.mode == DrawCircle_Mode.Center) {
                    let x1 = this.x - (this.nx - this.x);
                    let y1 = this.y - (this.ny - this.y);
                    DrawTool.DrawCircle_Perfect(priview, x1 - offx, y1 - offy, this.nx - offx, this.ny - offx, color, this.linewidth, pixelsizew, pixelsizeh);
                }
                else if (this.mode == DrawCircle_Mode.TwoPoint) {
                    DrawTool.DrawCircle_Perfect(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
                }
                else if (this.mode == DrawCircle_Mode.OutRect) {
                    DrawTool.DrawCircle_InBox(priview, this.x - offx, this.y - offy, this.nx - offx, this.ny - offy, color, this.linewidth, pixelsizew, pixelsizeh);
                }
            }
        }
        { //画提示
            priview.fillStyle = color.toString();
            let g = color.R / 255 * 0.4 + color.G / 255 * 0.5 + color.B / 255 * 0.1;
            if (g < 0.6) {
                priview.strokeStyle = "#fff";
            }
            else {
                priview.strokeStyle = "#000";
            }
            x = (x - offx) | 0;
            y = (y - offy) | 0;
            priview.fillRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
            priview.strokeRect(x * pixelsizew, y * pixelsizeh, this.linewidth * pixelsizew, this.linewidth * pixelsizeh);
        }
    }
}
//摆放模板图片
class Model_Tool extends DrawTool {
    constructor() {
        super(...arguments);
        this.Align = 1;
    }
    OnSet() {
        this.editor.toolbox_model.Show();
        this.editor.toolbox_color.Hide();
    }
    OnLeftDown(area, x, y, color) {
        let img = this.editor.toolbox_model_bar.getPickImg();
        if (img == null)
            return;
        let _r2d = area.getContext();
        x = ((x / this.Align) | 0) * this.Align;
        y = ((y / this.Align) | 0) * this.Align;
        _r2d.drawImage(img, x, y);
        area.updateBitmap();
        this.editor.history.TrySave("拜访模板");
    }
    OnLeftMove(area, x, y, color) {
    }
    OnLeftUp(area, x, y, color) {
    }
    OnPreview_InCanvas(priview, x, y, offx, offy, pixelsizew, pixelsizeh, color) {
        let img = this.editor.toolbox_model_bar.getPickImg();
        if (img == null)
            return;
        x = ((x / this.Align) | 0) * this.Align;
        y = ((y / this.Align) | 0) * this.Align;
        x = (x - offx) | 0;
        y = (y - offy) | 0;
        priview.globalAlpha = 0.5;
        priview.drawImage(img, 0, 0, img.width, img.height, x * pixelsizew, y * pixelsizeh, img.width * pixelsizew, img.height * pixelsizeh);
        priview.globalAlpha = 1;
        //priview.strokeRect(x * pixelsizew, y * pixelsizeh, 1 * pixelsizew, 1 * pixelsizeh);
    }
    SetLineWidth(width) {
    }
}
class DrawToolCenter {
    static Init(editor) {
        this.mapTool["pencil"] = new Pencil_Tool(editor);
        this.mapTool["earse"] = new Earser_Tool(editor);
        this.mapTool["drawline"] = new DrawLine_Tool(editor);
        this.mapTool["drawrect"] = new DrawRect_Tool(editor);
        this.mapTool["drawcircle1"] = new DrawCircle_Tool(editor, DrawCircle_Mode.Center);
        this.mapTool["drawcircle2"] = new DrawCircle_Tool(editor, DrawCircle_Mode.TwoPoint);
        this.mapTool["drawcircle_out"] = new DrawCircle_Tool(editor, DrawCircle_Mode.OutRect);
        this.mapTool["pick"] = new Pick_Tool(editor);
        this.mapTool["fill"] = new Fill_Tool(editor);
        this.mapTool["filltran"] = new Fill_Tool(editor, true);
        this.mapTool["select"] = new Select_Tool(editor);
        this.mapTool["move"] = new Move_Tool(editor);
        this.mapTool["rotate"] = new Rotate_Tool(editor);
        this.mapTool["model"] = new Model_Tool(editor);
    }
    static GetDrawTool(tag) {
        let tool = this.mapTool[tag];
        return tool;
    }
}
DrawToolCenter.mapTool = {};

//drawlayer 表示画布的一层
//暂时不做多图层了，意义不大。
var __awaiter$4 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class ImageBlock {
    constructor() {
        this.type = "imageblock";
    }
}
class DrawLayer {
    constructor() {
        this._edit_img = new DrawArea(32, 32); //编辑画板
        this.haveSelectData = false;
        //选区只是一个变量
        this._select = null;
    }
    getSelect() {
        return this._select;
    }
    Select(select) {
        if (this.haveSelectData) {
            this.applySelectData();
        }
        this._select = select;
    }
    Select_Cancel() {
        if (this.haveSelectData) {
            this.applySelectData();
        }
        this._select = null;
    }
    Select_ImgClear() {
        if (this._select_img == null)
            this._select_img = new DrawArea(this._edit_img.getWidth(), this._edit_img.getHeight());
        this._select_img.ClearRect(0, 0, this.getWidth(), this.getHeight());
    }
    Select_ImgDrawImage(img, x, y, tx = 0, ty = 0, rotate = 0) {
        if (this._select_img == null)
            this._select_img = new DrawArea(this._edit_img.getWidth(), this._edit_img.getHeight());
        let c2d = this._select_img.getContext();
        c2d.translate(tx, ty);
        c2d.rotate(rotate);
        this._select_img.getContext().drawImage(img, x, y);
        c2d.resetTransform();
        this._select_img.updateBitmap();
    }
    Select_ImgDrawImageScale(img, srcrange, xscale, yscale) {
        if (this._select_img == null)
            this._select_img = new DrawArea(this._edit_img.getWidth(), this._edit_img.getHeight());
        let c2d = this._select_img.getContext();
        let sx = srcrange.x1;
        let sy = srcrange.y1;
        let w = srcrange.x2 - srcrange.x1;
        let h = srcrange.y2 - srcrange.y1;
        let cx = (srcrange.x2 + srcrange.x1) / 2;
        let cy = (srcrange.y2 + srcrange.y1) / 2;
        let nx = (cx - w / 2 * xscale) | 0;
        let ny = (cy - h / 2 * yscale) | 0;
        let nw = (w * xscale) | 0;
        let nh = (h * yscale) | 0;
        c2d.drawImage(img, sx, sy, w, h, nx, ny, nw, nh);
        this._select_img.updateBitmap();
    }
    Select_CopyDataToJson() {
        if (this._select == null) {
            throw new Error("not have a select value.");
        }
        let data = this._edit_img.getContext().getImageData(this._select.x1, this._select.y1, this._select.x2 - this._select.x1 + 1, this._select.y2 - this._select.y1 + 1);
        let block = new ImageBlock();
        block.x = this._select.x1;
        block.y = this._select.y1;
        block.width = data.width;
        block.height = data.height;
        block.hexdata = IO.Hex2Str(data.data);
        return block;
    }
    Select_CopyDataToBlob() {
        return __awaiter$4(this, void 0, void 0, function* () {
            if (this._select == null) {
                throw new Error("not have a select value.");
            }
            let data = this._edit_img.getContext().getImageData(this._select.x1, this._select.y1, this._select.x2 - this._select.x1 + 1, this._select.y2 - this._select.y1 + 1);
            let b = yield ImgTool.ImgData2BlobAsync(data);
            // let b = await this._edit_img.getCanvas().convertToBlob({ "type": "image/png" });
            return b;
            // let block = new ImageBlock();
            // block.x = this._select.x1;
            // block.y = this._select.y1;
            // block.width = data.width;
            // block.height = data.height;
            // block.hexdata = IO.Hex2Str(data.data);
            // return block;
        });
    }
    Select_CutDataToJson() {
        let b = this.Select_CopyDataToJson();
        this._edit_img.getContext().clearRect(this._select.x1, this._select.y1, this._select.x2 - this._select.x1 + 1, this._select.y2 - this._select.y1 + 1);
        this._edit_img.updateBitmap();
        return b;
    }
    Select_FromImg(img) {
        if (this.haveSelectData)
            this.applySelectData();
        let data = ImgTool.Img2Data(img);
        if (this._select == null) {
            this._select = new RectRange(0, 0, img.width, img.height);
        }
        if (this._select_img == null)
            this._select_img = new DrawArea(this._edit_img.getWidth(), this._edit_img.getHeight());
        this._select.x1 = 0;
        this._select.y1 = 0;
        this._select.x2 = img.width - 1;
        this._select.y2 = img.height - 1;
        this._select_img.getContext().putImageData(data, this._select.x1, this._select.y1);
        this._select_img.updateBitmap();
        this.haveSelectData = true;
    }
    Select_FromJson(json) {
        if (this.haveSelectData)
            this.applySelectData();
        if (this._select == null) {
            this._select = new RectRange(json.x, json.y, json.x + json.width, json.y + json.height);
        }
        if (this._select_img == null)
            this._select_img = new DrawArea(this._edit_img.getWidth(), this._edit_img.getHeight());
        let data = new ImageData(json.width, json.height);
        let _data = IO.Str2Hex(json.hexdata);
        for (var i = 0; i < _data.length; i++)
            data.data[i] = _data[i];
        this._select.x1 = json.x;
        this._select.y1 = json.y;
        this._select.x2 = json.x + json.width - 1;
        this._select.y2 = json.y + json.height - 1;
        this._select_img.getContext().putImageData(data, this._select.x1, this._select.y1);
        this._select_img.updateBitmap();
        this.haveSelectData = true;
    }
    SetSelectData(range, data) {
        if (this.haveSelectData)
            this.applySelectData();
        if (range == null) {
            this._select = null;
            return;
        }
        this._select = range.Clone();
        if (this._select_img == null)
            this._select_img = new DrawArea(range.x2 - range.x1, range.y2 - range.y1);
        let bdata = new ImageData(range.x2 - range.x1, range.y2 - range.y1);
        bdata.data.set(data);
        this._select_img.getContext().putImageData(bdata, this._select.x1, this._select.y1);
        this._select_img.updateBitmap();
        this.haveSelectData = true;
    }
    SetEditData(data) {
        let bdata = new ImageData(this.getWidth(), this.getHeight());
        bdata.data.set(data);
        this._edit_img.getContext().putImageData(bdata, 0, 0);
        this._edit_img.updateBitmap();
    }
    //将选区拆到单独一层
    copyDataToSelect() {
        if (this._select == null) {
            throw new Error("not have a select value.");
        }
        let data = this._edit_img.getContext().getImageData(this._select.x1, this._select.y1, this._select.x2 - this._select.x1 + 1, this._select.y2 - this._select.y1 + 1);
        if (this._select_img == null)
            this._select_img = new DrawArea(this._edit_img.getWidth(), this._edit_img.getHeight());
        this._select_img.getContext().putImageData(data, this._select.x1, this._select.y1);
        this._select_img.updateBitmap();
        this.haveSelectData = true;
    }
    cutDataToSelect() {
        if (this._select == null) {
            throw new Error("not have a select value.");
        }
        this.copyDataToSelect();
        this._edit_img.getContext().clearRect(this._select.x1, this._select.y1, this._select.x2 - this._select.x1 + 1, this._select.y2 - this._select.y1 + 1);
        this._edit_img.updateBitmap();
    }
    //将选区合并回来
    applySelectData() {
        if (this.haveSelectData == true) {
            this.haveSelectData = false;
            let bmp = this._select_img.getBitmap();
            this._edit_img.getContext().drawImage(bmp, 0, 0);
            this._edit_img.updateBitmap();
            this.Select_ImgClear();
        }
    }
    dropSelectData() {
        if (this.haveSelectData == true) {
            this.haveSelectData = false;
            this.Select_ImgClear();
        }
    }
    getBitmap() {
        return this._edit_img.getBitmap();
    }
    getBitmapSelect() {
        if (this.haveSelectData)
            return this._select_img.getBitmap();
        else
            return null;
    }
    getBitmapData() {
        return this._edit_img.getContext().getImageData(0, 0, this.getWidth(), this.getHeight());
    }
    getBitmapDataSelect() {
        if (this.haveSelectData)
            return this._select_img.getContext().getImageData(this._select.x1, this._select.y1, this._select.x2 - this._select.x1, this._select.y2 - this._select.y1);
        else
            return null;
    }
    DrawArea_Init(img) {
        this._edit_img.DrawArea_Init(img);
    }
    Resize_Scale(neww, newh, linear) {
        this._edit_img.Resize_Scale(neww, newh, linear);
    }
    Resize_Cut(neww, newh, dirx, diry) {
        this._edit_img.Resize_Cut(neww, newh, dirx, diry);
    }
    setWidth(width) {
        this._edit_img.setWidth(width);
    }
    setHeight(height) {
        this._edit_img.setHeight(height);
    }
    getWidth() {
        return this._edit_img.getWidth();
    }
    getHeight() {
        return this._edit_img.getHeight();
    }
    updateBitmap() {
        this._edit_img.updateBitmap();
    }
    getContext() {
        return this._edit_img.getContext();
    }
    ClearRect(x, y, w, h) {
        this._edit_img.ClearRect(x, y, w, h);
    }
}

//切分画板相应功能
class PixelEdit_DrawCanvas {
    constructor() {
        this.drawColor = new Color32(0, 0, 0, 255);
        //图层相关
        this._layers = [];
        this._scale = 1.0;
        this.op_grid = true;
        this.op_backpicshow = true;
        this._layers.push(new DrawLayer());
        this.op_backlayer = new DrawLayer();
        this.op_backlayer.updateBitmap();
        this._finalbitmap = new DrawArea(32, 32);
        this._finalbitmap.updateBitmap();
    }
    IsSelect() {
        return this.getCurrentLayer().getSelect() != null;
    }
    setDrawColor(color) {
        this.drawColor = color.Clone();
    }
    getDrawColor() {
        return this.drawColor.Clone();
    }
    setBackColor(color) {
        this.canvas.setBackColor(color);
    }
    getCurrentLayer() {
        return this._layers[0];
    }
    GetFinalBitmap() {
        return this._finalbitmap;
    }
    SetSize(width, height) {
        this._finalbitmap.setWidth(width);
        this._finalbitmap.setHeight(height);
        for (var i = 0; i < this._layers.length; i++) {
            this._layers[i].setWidth(width);
            this._layers[i].setHeight(width);
        }
        this.op_backlayer.setWidth(width);
        this.op_backlayer.setHeight(height);
    }
    getWidth() {
        return this._finalbitmap.getWidth();
    }
    getHeight() {
        return this._finalbitmap.getHeight();
    }
    Resize_Scale(neww, newh, linear) {
        this._finalbitmap.setWidth(neww);
        this._finalbitmap.setHeight(newh);
        for (var i = 0; i < this._layers.length; i++) {
            this._layers[i].Resize_Scale(neww, newh, linear);
        }
        this.op_backlayer.Resize_Scale(neww, newh, linear);
    }
    Resize_Cut(neww, newh, dirx, diry) {
        this._finalbitmap.setWidth(neww);
        this._finalbitmap.setHeight(newh);
        for (var i = 0; i < this._layers.length; i++) {
            this._layers[i].Resize_Cut(neww, newh, dirx, diry);
        }
        this.op_backlayer.Resize_Cut(neww, newh, dirx, diry);
    }
    Init(editor) {
        this.editor = editor;
        let canvas = this.canvas;
        let priview = editor.priview;
        canvas.RePaint = this.RePaint.bind(this);
        let press = false;
        let ctrlmode = false;
        canvas._root.onmousedown = (e) => {
            //canvas仅限左键操作
            if (e.button != 0)
                return;
            let x = e.offsetX / this._scale + editor.priview.rectX;
            let y = e.offsetY / this._scale + editor.priview.rectY;
            if (!e.ctrlKey) {
                ctrlmode = false;
                this.OnToolMouseLeftDown(x | 0, y | 0);
            }
            else {
                ctrlmode = true;
            }
            press = true;
        };
        canvas._root.onmousemove = (e) => {
            let x = this._LastDrawX = e.offsetX / this._scale + editor.priview.rectX;
            let y = this._LastDrawY = e.offsetY / this._scale + editor.priview.rectY;
            //console.log(e.button);
            let _elayer = canvas._root;
            if (ctrlmode && press) {
                //ctrl 用来移动画布
                //处理点在红框之外
                let fh = _elayer.clientHeight;
                let scale = fh / editor.priview.imgheight;
                //移动红框
                editor.priview.rectX -= e.movementX / scale;
                editor.priview.rectY -= e.movementY / scale;
                //不让红框离开canvas
                editor.priview.Refresh();
            }
            else if (press) {
                //let idata = new ImageData(21, 21);
                this.OnToolMouseLeftMove(x | 0, y | 0);
            }
            editor.priview.Refresh();
        };
        window.addEventListener("mouseup", (e) => {
            if (press) {
                press = false;
                let x = e.offsetX / this._scale + editor.priview.rectX;
                let y = e.offsetY / this._scale + editor.priview.rectY;
                if (!ctrlmode) {
                    this.OnToolMouseLeftUp(x | 0, y | 0);
                }
            }
        });
        //先刷一次
        canvas.Refresh();
        //canvas.getC2D().drawImage(img, 0, 0, img.width * 4, img.height * 4);
        priview.onChange = () => {
            canvas.Refresh();
        };
        priview.onChangeScale = (v) => {
            this._scale = v;
            this.RePaint();
        };
        canvas._root.addEventListener('mousewheel', (e) => {
            if (e.wheelDelta) {
                let delta = e.wheelDelta;
                if (event.ctrlKey) {
                    if (delta > 0)
                        editor.priview._range.valueAdd();
                    else if (delta < 0)
                        editor.priview._range.valueDec();
                }
                else {
                    this.OnToolMouseWheel(delta);
                }
            }
        });
    }
    RePaint() {
        if (this.editor == null || this.editor.priview == null)
            return;
        let _c2d = this.canvas.getC2D();
        let radio = _c2d.canvas.width / _c2d.canvas.height;
        this.editor.priview.rectHeight = _c2d.canvas.height / this._scale;
        this.editor.priview.rectWidth = this.editor.priview.rectHeight * radio;
        _c2d.imageSmoothingEnabled = false;
        let x = this.editor.priview.rectX | 0;
        let y = this.editor.priview.rectY | 0;
        let w = this.editor.priview.rectWidth | 0;
        let h = this.editor.priview.rectHeight | 0;
        //绘制图层
        this._finalbitmap.getContext().clearRect(0, 0, this._finalbitmap.getWidth(), this._finalbitmap.getHeight());
        for (var i = 0; i < this._layers.length; i++) {
            let img = this._layers[i].getBitmap();
            this._finalbitmap.getContext().drawImage(img, 0, 0);
            let imgselect = this._layers[i].getBitmapSelect();
            if (imgselect != null)
                this._finalbitmap.getContext().drawImage(imgselect, 0, 0);
        }
        this._finalbitmap.updateBitmap();
        let fimg = this._finalbitmap.getBitmap();
        //绘制参考层
        if (this.op_backpicshow) {
            let img = this.op_backlayer.getBitmap();
            if (img != null)
                _c2d.drawImage(img, x, y, w, h, 0, 0, _c2d.canvas.width | 0, _c2d.canvas.height | 0);
            let imgselect = this.op_backlayer.getBitmapSelect();
            if (imgselect != null)
                _c2d.drawImage(imgselect, x, y, w, h, 0, 0, _c2d.canvas.width | 0, _c2d.canvas.height | 0);
        }
        _c2d.drawImage(this._finalbitmap.getBitmap(), x, y, w, h, 0, 0, _c2d.canvas.width | 0, _c2d.canvas.height | 0);
        this.editor.priview.Refresh();
        let pixelw = _c2d.canvas.width / w;
        let pixelh = _c2d.canvas.height / h;
        if (this.op_grid) {
            this.paint_Grid(pixelw, pixelh);
        }
        //预览图标
        this.OnToolPreview_InCanvas(this._LastDrawX, this._LastDrawY, pixelw, pixelh);
        //遮蔽超出区域
        if (x + w > fimg.width) {
            let w2 = fimg.width - x;
            _c2d.fillStyle = "#777";
            _c2d.fillRect(pixelw * w2, 0, _c2d.canvas.width - pixelw * w2, _c2d.canvas.height);
        }
        if (y + h > fimg.height) {
            let h2 = fimg.height - y;
            _c2d.fillStyle = "#777";
            _c2d.fillRect(0, pixelh * h2, _c2d.canvas.width, _c2d.canvas.height - pixelh * h2);
        }
    }
    paint_Grid(pixelw, pixelh) {
        let _c2d = this.canvas.getC2D();
        let x = this.editor.priview.rectX | 0;
        let y = this.editor.priview.rectY | 0;
        this.editor.priview.rectWidth | 0;
        this.editor.priview.rectHeight | 0;
        //不可避免的会出现一点偏差，重新算一个像素的宽度
        {
            let gridscale = 16;
            { //画浅格
                _c2d.strokeStyle = "#333";
                _c2d.beginPath();
                //不可避免的会出现一点偏差，重新算一个像素的宽度
                //显示几个像素为一格
                if (this._scale >= 16) {
                    gridscale = 1.0;
                }
                else if (this._scale >= 8.0) {
                    gridscale = 2.0;
                }
                else if (this._scale >= 4.0) {
                    gridscale = 4.0;
                }
                else if (this._scale >= 2.0) {
                    gridscale = 8.0;
                }
                else {
                    gridscale = 16.0;
                }
                //画横线
                for (var i = 0; i < _c2d.canvas.height; i += pixelh * gridscale) {
                    _c2d.moveTo(0, i);
                    _c2d.lineTo(_c2d.canvas.width, i);
                }
                //画竖线
                for (var i = 0; i < _c2d.canvas.width; i += pixelw * gridscale) {
                    _c2d.moveTo(i, 0);
                    _c2d.lineTo(i, _c2d.canvas.height);
                }
                _c2d.closePath();
                _c2d.stroke();
            }
            if (this._scale > 1.0) { //画深格
                _c2d.strokeStyle = "#888";
                _c2d.beginPath();
                //显示几个像素为一格
                let deepw = (y % 16);
                //画横线
                for (var i = 0; i < _c2d.canvas.height; i += pixelh * gridscale) {
                    if (deepw >= 16) {
                        _c2d.moveTo(0, i);
                        _c2d.lineTo(_c2d.canvas.width, i);
                        deepw = 0;
                    }
                    deepw += gridscale;
                }
                deepw = (x % 16);
                //画竖线
                for (var i = 0; i < _c2d.canvas.width; i += pixelw * gridscale) {
                    if (deepw >= 16) {
                        _c2d.moveTo(i, 0);
                        _c2d.lineTo(i, _c2d.canvas.height);
                        deepw = 0;
                    }
                    deepw += gridscale;
                }
                _c2d.closePath();
                _c2d.stroke();
            }
        }
    }
    OnToolMouseLeftDown(x, y) {
        let tag = this.editor.toolbar.getPickTag();
        let dot = parseInt(this.editor.toolbarsize.getPickTag());
        let color = this.getDrawColor();
        let tool = DrawToolCenter.GetDrawTool(tag);
        if (tool != undefined) {
            tool.SetLineWidth(dot);
            tool.OnLeftDown(this.getCurrentLayer(), x, y, color);
            this.RePaint();
        }
    }
    OnToolMouseLeftMove(x, y) {
        let tag = this.editor.toolbar.getPickTag();
        let dot = parseInt(this.editor.toolbarsize.getPickTag());
        let color = this.getDrawColor();
        let tool = DrawToolCenter.GetDrawTool(tag);
        if (tool != undefined) {
            tool.SetLineWidth(dot);
            tool.OnLeftMove(this.getCurrentLayer(), x, y, color);
            this.RePaint();
        }
    }
    OnToolMouseLeftUp(x, y) {
        let tag = this.editor.toolbar.getPickTag();
        let color = this.getDrawColor();
        let tool = DrawToolCenter.GetDrawTool(tag);
        if (tool != undefined) {
            tool.OnLeftUp(this.getCurrentLayer(), x, y, color);
            this.RePaint();
        }
    }
    OnToolMouseWheel(delta) {
        let tag = this.editor.toolbar.getPickTag();
        let tool = DrawToolCenter.GetDrawTool(tag);
        if (tool != undefined) {
            tool.OnToolMouseWheel(this.getCurrentLayer(), delta);
            this.RePaint();
        }
    }
    OnToolPreview_InCanvas(x, y, pixelw, pixelh) {
        let tag = this.editor.toolbar.getPickTag();
        let color = this.getDrawColor();
        let tool = DrawToolCenter.GetDrawTool(tag);
        if (tool != undefined) {
            tool.OnPreview_InCanvas(this.canvas._c2d, x, y, this.editor.priview.rectX | 0, this.editor.priview.rectY | 0, pixelw, pixelh, color);
        }
        let offx = this.editor.priview.rectX;
        let offy = this.editor.priview.rectY;
        //绘制选区
        if (this.editor.drawCanvas.getCurrentLayer().getSelect() != null) {
            let timer = this.editor.timer * 2;
            if (timer > 1)
                timer = 2 - timer;
            let s = this.editor.drawCanvas.getCurrentLayer().getSelect();
            let c = new Color32(255 * timer, 58, 255 * (1 - timer), 200);
            this.canvas._c2d.globalAlpha = 0.5;
            DrawTool.DrawRect(this.canvas._c2d, s.x1 - offx, s.y1 - offy, s.x2 - offx, s.y2 - offy, c, 1, pixelw, pixelh);
            this.canvas._c2d.globalAlpha = 1.0;
        }
    }
}

class Dir2 extends BaseElement {
    constructor(title = "", value = null) {
        super();
        this._divs = [];
        this._value = { x: 0, y: 0 };
        this._root = document.createElement("div");
        this._root.style.fontSize = "0";
        //this.Style_Fill();
        let span = document.createElement("span");
        span.textContent = title;
        span.style.fontSize = "16px";
        this._root.appendChild(span);
        let br = document.createElement("br");
        this._root.appendChild(br);
        for (var y = -1; y <= 1; y++) {
            for (var x = -1; x <= 1; x++) {
                let div = document.createElement("div");
                div.style.display = "inline-block";
                div.style.width = "32px";
                div.style.height = "32px";
                div.style.border = "2px solid #ccc";
                div.style.position = "relative";
                this._root.appendChild(div);
                div.title = x + "," + y;
                this._divs.push(div);
                let sx = x;
                let sy = y;
                div.onmousedown = () => {
                    this._value.x = sx;
                    this._value.y = sy;
                    this.updatePick();
                };
            }
            let br = document.createElement("br");
            this._root.appendChild(br);
        }
        this.updatePick();
    }
    getValue() {
        return this._value;
    }
    updatePick() {
        for (var i = 0; i < 9; i++) {
            let y = ((i / 3) | 0) - 1;
            let x = ((i % 3) | 0) - 1;
            if (x == this._value.x && y == this._value.y) {
                this._divs[i].style.backgroundColor = "#3c3";
            }
            else {
                this._divs[i].style.backgroundColor = "#333";
            }
        }
    }
}

var __awaiter$3 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class BaseDialog {
    constructor() {
        this._divBack = document.createElement("div");
        this._divBack.style.position = "absolute";
        this._divBack.style.left = "0px";
        this._divBack.style.right = "0px";
        this._divBack.style.top = "0px";
        this._divBack.style.bottom = "0px";
        this._divBack.style.backgroundColor = "rgba(0,0,0,0.75)";
        this._panel = new Panel();
        this._divBack.appendChild(this._panel._root);
        this._panel._root.style.position = "absolute";
        this._panel._root.style.left = "25%";
        this._panel._root.style.right = "25%";
        this._panel._root.style.top = "25%";
        this._panel._root.style.bottom = "25%";
        this._panel._root.style.border = "2px solid #fff";
        this._panel._root.style.textAlign = "center";
    }
    Show() {
        return __awaiter$3(this, void 0, void 0, function* () {
            this._done = false;
            document.body.appendChild(this._divBack);
            while (this._done == false) {
                yield IO.sleep(1);
            }
            this._divBack.remove();
            return this._value;
        });
    }
}
class MessageDialog extends BaseDialog {
    constructor(title, msgs = null) {
        super();
        this.divCenter = new Panel();
        let divCenter = this.divCenter = new Panel();
        divCenter.SetBorder(0);
        divCenter.SetVCenter();
        divCenter._root.style.top = "50%";
        divCenter._root.style.position = "relative";
        divCenter._root.style.transform = "translateY(-50%)";
        this._panel.AddChild(divCenter);
        this.AddLabel(title, "middle");
        if (msgs != null) {
            for (var i = 0; i < msgs.length; i++) {
                let msg = msgs[i].txt;
                if (msg == "") {
                    this.AddBr();
                }
                else
                    this.AddLabel(msg, msgs[i].align);
            }
        }
        this.AddBr();
        let btn = new Button("Close", () => {
            this._done = true;
        });
        this.divCenter.AddChild(btn);
    }
    AddLabel(txt, align = "left") {
        let label = new Label(txt);
        label._root.style.textAlign = align;
        this.divCenter.AddChild(label);
    }
    AddBr() {
        this.divCenter._root.appendChild(document.createElement("br"));
    }
}
var ValueType;
(function (ValueType) {
    ValueType[ValueType["BOOL"] = 0] = "BOOL";
    ValueType[ValueType["STRING"] = 1] = "STRING";
    ValueType[ValueType["NUMBER"] = 2] = "NUMBER";
    ValueType[ValueType["DIR2"] = 3] = "DIR2";
})(ValueType || (ValueType = {}));
class ValuesDialog extends BaseDialog {
    constructor(title, vs) {
        super();
        let l = new Label(title);
        this._panel.AddChild(l);
        let ts = [];
        for (var i = 0; i < vs.length; i++) {
            if (vs[i].type == ValueType.NUMBER || vs[i].type == ValueType.STRING) {
                let t1 = new TextBox(vs[i].name, vs[i].defvalue.toString());
                this._panel.AddChild(t1);
                ts.push(t1);
            }
            else if (vs[i].type == ValueType.BOOL) {
                let t1 = new Toggle(vs[i].name, vs[i].defvalue);
                this._panel.AddChild(t1);
                ts.push(t1);
            }
            else if (vs[i].type == ValueType.DIR2) {
                let t1 = new Dir2(vs[i].name, vs[i].defvalue);
                this._panel.AddChild(t1);
                ts.push(t1);
            }
        }
        let btn = new Button("OK", () => __awaiter$3(this, void 0, void 0, function* () {
            try {
                this._value = [];
                for (var i = 0; i < vs.length; i++) {
                    if (vs[i].type == ValueType.NUMBER) {
                        let v = parseInt(ts[i].getValue());
                        this._value.push(v);
                    }
                    else {
                        let b = ts[i].getValue();
                        this._value.push(b);
                    }
                }
                if (this.onCheck != null) {
                    if (!this.onCheck(this._value)) {
                        throw new Error("检查失败");
                    }
                }
            }
            catch (e) {
                let msg = new MessageDialog("Error:" + e);
                yield msg.Show();
                return;
            }
            this._done = true;
        }));
        btn.Style_Size(100, 24);
        this._panel.AddChild(btn);
        let btn2 = new Button("Cancel", () => {
            this._value = null;
            this._done = true;
        });
        this._panel.AddChild(btn2);
    }
}

var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class PixelEditor_Function {
    static InitToolbar(toolbar) {
        toolbar.addButton("media/pen.png", "pencil", "铅笔");
        toolbar.addButton("media/line.png", "drawline", "画线");
        toolbar.addButton("media/rect.png", "drawrect", "画方");
        toolbar.addButton("media/circle.png", "drawcircle1", "中心点画圆");
        toolbar.addButton("media/circle2.png", "drawcircle2", "对角画圆");
        toolbar.addButton("media/circle_out.png", "drawcircle_out", "画矩形外接圆");
        toolbar.addButton("media/select.png", "select", "选取");
        toolbar.addButton("media/move.png", "move", "移动选区");
        toolbar.addButton("media/rotate.png", "rotate", "旋转选区");
        toolbar.addButton("media/pick.png", "pick", "拾色器");
        toolbar.addButton("media/fill.png", "fill", "填充");
        toolbar.addButton("media/model.png", "model", "摆放模板-coming...");
        toolbar.addButton("media/earse.png", "earse", "橡皮擦");
        toolbar.addButton("media/filltran.png", "filltran", "填充透明色");
        toolbar.addButton("media/picklayer.png", "picklayer", "选取层-coming...", "#c33");
        // toolbar.addButton("media/pick.png", "pick", "拾色器");
        // 
    }
    static select_All(editor) {
        let all = new RectRange(0, 0, editor.drawCanvas.getWidth() - 1, editor.drawCanvas.getHeight() - 1);
        editor.drawCanvas.getCurrentLayer().Select(all);
    }
    static select_Desel(editor) {
        editor.drawCanvas.getCurrentLayer().Select_Cancel();
        editor.drawCanvas.RePaint();
    }
    static select_C(editor) {
        return __awaiter$2(this, void 0, void 0, function* () {
            let b = yield editor.drawCanvas.getCurrentLayer().Select_CopyDataToBlob();
            yield navigator.clipboard.write([new ClipboardItem({ "image/png": b })]);
            //let json = editor.drawCanvas.getCurrentLayer().Select_CopyDataToJson();
            //await navigator.clipboard.writeText(JSON.stringify(json));
        });
    }
    static select_V(editor) {
        return __awaiter$2(this, void 0, void 0, function* () {
            let citems = yield navigator.clipboard.read();
            for (var i = 0; i < citems.length; i++) {
                let t = citems[i].types;
                for (var j = 0; j < t.length; j++) {
                    console.log("clip type=" + citems[i].types[j]);
                    if (citems[i].types[j] == "image/png") {
                        let imgb = yield citems[i].getType("image/png");
                        let url = URL.createObjectURL(imgb);
                        let img = yield ImgTool.Url2ImgAsync(url);
                        editor.drawCanvas.getCurrentLayer().applySelectData();
                        editor.drawCanvas.getCurrentLayer().Select_FromImg(img);
                        let tag = editor.toolbar.getPickTag();
                        DrawToolCenter.GetDrawTool(tag).OnSet();
                        editor.drawCanvas.RePaint();
                        return;
                    }
                }
            }
            let txt = yield navigator.clipboard.readText();
            try {
                let json = JSON.parse(txt);
                if (json["type"] == "imageblock") {
                    editor.drawCanvas.getCurrentLayer().applySelectData();
                    editor.drawCanvas.getCurrentLayer().Select_FromJson(json);
                    let tag = editor.toolbar.getPickTag();
                    DrawToolCenter.GetDrawTool(tag).OnSet();
                    editor.drawCanvas.RePaint();
                }
            }
            catch (_a) {
                console.log("Ctrl+V error.");
            }
        });
    }
    static select_X(editor) {
        return __awaiter$2(this, void 0, void 0, function* () {
            let json = editor.drawCanvas.getCurrentLayer().Select_CutDataToJson();
            yield navigator.clipboard.writeText(JSON.stringify(json));
            editor.drawCanvas.RePaint();
        });
    }
    static history_Z(editor) {
        return __awaiter$2(this, void 0, void 0, function* () {
            editor.history.GoLast();
        });
    }
    static history_Y(editor) {
        return __awaiter$2(this, void 0, void 0, function* () {
            editor.history.GoNext();
        });
    }
    static ResetModels(editor, path) {
        return __awaiter$2(this, void 0, void 0, function* () {
            editor.toolbox_model_bar._root.parentElement.style.overflowX = "hidden";
            editor.toolbox_model_bar._root.parentElement.style.overflowY = "scroll";
            editor.toolbox_model_bar.btnsize = 36;
            editor.toolbox_model_bar.clearButton();
            try {
                let files = yield IO.FindFile(path, 5);
                for (var i = 0; i < files.length; i++) {
                    let f = files[i];
                    //限制下文件容量，模板文件就不可能大
                    if (f.name.includes(".png") && f.size < 100 * 1024) {
                        console.log("load file:" + f.name);
                        let bin = yield IO.LoadBinaryFile(f.name);
                        console.log("load file succ.");
                        //let img = await ImgTool.Bin2ImgAsync(bin);
                        let url = ImgTool.Bin2Url(bin);
                        editor.toolbox_model_bar.addButton(url, f.name, f.name);
                    }
                }
            }
            catch (e) {
                let d = new MessageDialog("error", [{ "txt": "error:" + e, align: "center" }]);
                yield d.Show();
            }
        });
    }
    static InitFunc(editor) {
        this.InitToolbar(editor.toolbar);
        //this.group_func.SetTitle("保存功能");
        window.addEventListener("keydown", (e) => {
            if (e.key == "s" && (e.metaKey || e.ctrlKey)) {
                e.preventDefault();
                editor._save();
            }
            if (e.key == "a" && (e.metaKey || e.ctrlKey)) {
                //权限
                e.preventDefault();
                this.select_All(editor);
            }
            if (e.key == "d" && (e.metaKey || e.ctrlKey)) {
                //取消选区
                e.preventDefault();
                this.select_Desel(editor);
            }
            if (e.key == "c" && (e.metaKey || e.ctrlKey)) {
                //复制
                e.preventDefault();
                this.select_C(editor);
            }
            if (e.key == "x" && (e.metaKey || e.ctrlKey)) {
                //剪切
                e.preventDefault();
                this.select_X(editor);
            }
            if (e.key == "v" && (e.metaKey || e.ctrlKey)) {
                //粘贴
                e.preventDefault();
                this.select_V(editor);
            }
            if (e.key == "z" && (e.metaKey || e.ctrlKey)) {
                //撤销
                e.preventDefault();
                this.history_Z(editor);
            }
            if (e.key == "y" && (e.metaKey || e.ctrlKey)) {
                //重做
                e.preventDefault();
                this.history_Y(editor);
            }
        });
        // this.group_func.AddChild(new DOM.Button("保存", async () => {
        //     this._save();
        // }));
        editor.menu = new Menu();
        editor.menu.AddItem("保存 CTRL+S", () => {
            editor._save();
        });
        editor.menu.AddItem("_", null);
        editor.menu.AddItem("参考线-隐藏", (btn) => {
            editor.drawCanvas.op_grid = !editor.drawCanvas.op_grid;
            editor.drawCanvas.RePaint();
            btn.textContent = editor.drawCanvas.op_grid ? "参考线-隐藏" : "参考线-显示";
        });
        editor.menu.AddItem("加载参考图(背景,不保存)", () => __awaiter$2(this, void 0, void 0, function* () {
            let d = new ValuesDialog("加载参考图", [{ "name": "文件名", "type": ValueType.STRING, "defvalue": "d:\\1.png" }]);
            let r = yield d.Show();
            if (r != null) {
                try {
                    let file = yield IO.LoadBinaryFile(r[0]);
                    let img = yield ImgTool.Bin2ImgAsync(file);
                    editor.drawCanvas.op_backlayer.getContext().clearRect(0, 0, editor.drawCanvas.getWidth(), editor.drawCanvas.getHeight());
                    editor.drawCanvas.op_backlayer.getContext().drawImage(img, 0, 0);
                    editor.drawCanvas.op_backlayer.updateBitmap();
                }
                catch (e) {
                    console.log("error:" + e);
                }
            }
        }));
        editor.menu.AddItem("参考图-隐藏", (btn) => {
            editor.drawCanvas.op_backpicshow = !editor.drawCanvas.op_backpicshow;
            editor.drawCanvas.RePaint();
            btn.textContent = editor.drawCanvas.op_backpicshow ? "参考图-隐藏" : "参考图-显示";
        });
        editor.menu.AddItem("_", null);
        editor.menu.AddItem("选区-全选 CTRL+A", () => {
            this.select_All(editor);
        });
        editor.menu.AddItem("选区-取消选区 CTRL+D", () => {
            this.select_Desel(editor);
        });
        editor.menu.AddItem("选区-复制 CTRL+C", () => {
            this.select_C(editor);
        });
        editor.menu.AddItem("选区-粘贴 CTRL+V", () => {
            this.select_V(editor);
        });
        editor.menu.AddItem("选区-剪切 CTRL+X", () => {
            this.select_X(editor);
        });
        editor.menu.AddItem("_", null);
        editor.menu.AddItem("加载模板图片", () => __awaiter$2(this, void 0, void 0, function* () {
            let d = new ValuesDialog("加载模板图片", [
                { name: "图片路径", defvalue: "pic", type: ValueType.STRING }
            ]);
            let r = yield d.Show();
            if (r != null) {
                this.ResetModels(editor, r[0]);
            }
        }));
        editor.menu.AddItem("模板对齐/1px", () => __awaiter$2(this, void 0, void 0, function* () {
            DrawToolCenter.GetDrawTool("model").Align = 1;
        }));
        editor.menu.AddItem("模板对齐/16px", () => __awaiter$2(this, void 0, void 0, function* () {
            DrawToolCenter.GetDrawTool("model").Align = 16;
        }));
        editor.menu.AddItem("模板对齐/32px", () => __awaiter$2(this, void 0, void 0, function* () {
            DrawToolCenter.GetDrawTool("model").Align = 32;
        }));
        editor.menu.AddItem("_", null);
        editor.menu.AddItem("图像尺寸-整体缩放", () => __awaiter$2(this, void 0, void 0, function* () {
            let sw = editor.drawCanvas.getWidth();
            let sh = editor.drawCanvas.getHeight();
            let d = new ValuesDialog("原尺寸: " + sw + " X " + sh, [
                { name: "宽", defvalue: sw, type: ValueType.NUMBER },
                { name: "高", defvalue: sh, type: ValueType.NUMBER },
                { name: "插值", defvalue: false, type: ValueType.BOOL }
            ]);
            d.onCheck = (v) => {
                if (isNaN(v[0]) || isNaN(v[1]) || v[0] < 8 || v[0] > 2048 || v[1] < 8 || v[1] > 2048) {
                    throw new Error("尺寸错误，限制8~2048");
                }
                return true;
            };
            let nv = yield d.Show();
            console.log("nv=" + JSON.stringify(nv));
            if (nv != null) {
                editor.drawCanvas.Resize_Scale(nv[0], nv[1], nv[2]);
                editor.priview.UpdateImgSize();
                editor.drawCanvas.RePaint();
            }
        }));
        editor.menu.AddItem("图像尺寸-裁切画布", () => __awaiter$2(this, void 0, void 0, function* () {
            let sw = editor.drawCanvas.getWidth();
            let sh = editor.drawCanvas.getHeight();
            let d = new ValuesDialog("原尺寸: " + sw + " X " + sh, [
                { name: "宽", defvalue: sw, type: ValueType.NUMBER },
                { name: "高", defvalue: sh, type: ValueType.NUMBER },
                { name: "方向", defvalue: { x: 0, y: 0 }, type: ValueType.DIR2 }
            ]);
            d.onCheck = (v) => {
                if (isNaN(v[0]) || isNaN(v[1]) || v[0] < 8 || v[0] > 2048 || v[1] < 8 || v[1] > 2048) {
                    throw new Error("尺寸错误，限制8~2048");
                }
                return true;
            };
            let nv = yield d.Show();
            console.log("nv=" + JSON.stringify(nv));
            if (nv != null) {
                editor.drawCanvas.Resize_Cut(nv[0], nv[1], nv[2].x, nv[2].y);
                editor.priview.UpdateImgSize();
                editor.drawCanvas.RePaint();
            }
        }));
        editor.menu.AddItem("_", null);
        editor.menu.AddItem("撤销 CTRL+Z", () => {
            this.history_Z(editor);
        });
        editor.menu.AddItem("重做 CTRL+A", () => {
            this.history_Y(editor);
        });
        editor.menu.AddItem("_", null);
        editor.menu.AddItem("关于", () => __awaiter$2(this, void 0, void 0, function* () {
            let msg = [];
            msg.push({ "txt": "左侧可选择线宽、绘图工具、调色板颜色、模板", align: "left" });
            msg.push({ "txt": "", align: "left" });
            msg.push({ "txt": "绘图功能有：", align: "left" });
            msg.push({ "txt": "绘图：", align: "left" });
            msg.push({ "txt": " 1.铅笔", align: "left" });
            msg.push({ "txt": " 2.画线", align: "left" });
            msg.push({ "txt": " 3.画矩形", align: "left" });
            msg.push({ "txt": " 4.画圆：中心 + 半径", align: "left" });
            msg.push({ "txt": " 5.画圆：两点", align: "left" });
            msg.push({ "txt": " 6.画圆：画一个边界在矩形之内的圆", align: "left" });
            msg.push({ "txt": " 7.橡皮擦：擦除为透明色", align: "left" });
            msg.push({ "txt": " 8.吸色器，从画布中吸取一个颜色作为调色板选中色", align: "left" });
            msg.push({ "txt": " 9.选区功能，建立一个矩形选区，所有的操作都限制在选区内。", align: "left" });
            msg.push({ "txt": "10.填色功能：填充一个固定的颜色到画布中。", align: "left" });
            msg.push({ "txt": "11.填透明色功能：填充透明色到画布中。", align: "left" });
            msg.push({ "txt": "12.摆放模板功能：将选中的模板摆放到画布上。", align: "left" });
            msg.push({ "txt": "", align: "left" });
            msg.push({ "txt": "按住Ctrl 键有几个特殊功能", align: "left" });
            msg.push({ "txt": "1.Ctrl 键 点选调色板，设置透明背景下看到的颜色", align: "left" });
            msg.push({ "txt": "1.Ctrl 键 在画布上拖拽鼠标，当画布过大时快速移动位置", align: "left" });
            msg.push({ "txt": "1.Ctrl 键 在画布上滚动鼠标，快速改变显示倍率", align: "left" });
            let d = new MessageDialog("===TTEngine(躺平引擎) 像素编辑器==", msg);
            yield d.Show();
        }));
        let _b = new Button("===菜单===", () => __awaiter$2(this, void 0, void 0, function* () {
            let pos = editor.menu.GetElemCenter(_b._root);
            editor.menu.Show(pos.x, pos.y);
        }));
        _b.Style_Fill();
        editor.group_func.AddChild(_b);
    }
}

/**
 * sha256-uint8array.ts
 */
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
const K = [
    0x428a2f98 | 0, 0x71374491 | 0, 0xb5c0fbcf | 0, 0xe9b5dba5 | 0,
    0x3956c25b | 0, 0x59f111f1 | 0, 0x923f82a4 | 0, 0xab1c5ed5 | 0,
    0xd807aa98 | 0, 0x12835b01 | 0, 0x243185be | 0, 0x550c7dc3 | 0,
    0x72be5d74 | 0, 0x80deb1fe | 0, 0x9bdc06a7 | 0, 0xc19bf174 | 0,
    0xe49b69c1 | 0, 0xefbe4786 | 0, 0x0fc19dc6 | 0, 0x240ca1cc | 0,
    0x2de92c6f | 0, 0x4a7484aa | 0, 0x5cb0a9dc | 0, 0x76f988da | 0,
    0x983e5152 | 0, 0xa831c66d | 0, 0xb00327c8 | 0, 0xbf597fc7 | 0,
    0xc6e00bf3 | 0, 0xd5a79147 | 0, 0x06ca6351 | 0, 0x14292967 | 0,
    0x27b70a85 | 0, 0x2e1b2138 | 0, 0x4d2c6dfc | 0, 0x53380d13 | 0,
    0x650a7354 | 0, 0x766a0abb | 0, 0x81c2c92e | 0, 0x92722c85 | 0,
    0xa2bfe8a1 | 0, 0xa81a664b | 0, 0xc24b8b70 | 0, 0xc76c51a3 | 0,
    0xd192e819 | 0, 0xd6990624 | 0, 0xf40e3585 | 0, 0x106aa070 | 0,
    0x19a4c116 | 0, 0x1e376c08 | 0, 0x2748774c | 0, 0x34b0bcb5 | 0,
    0x391c0cb3 | 0, 0x4ed8aa4a | 0, 0x5b9cca4f | 0, 0x682e6ff3 | 0,
    0x748f82ee | 0, 0x78a5636f | 0, 0x84c87814 | 0, 0x8cc70208 | 0,
    0x90befffa | 0, 0xa4506ceb | 0, 0xbef9a3f7 | 0, 0xc67178f2 | 0,
];
function Bin2Sha256(dat) {
    return new Hash().update(dat).digest("hex");
}
class Hash {
    constructor() {
        // first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
        this.A = 0x6a09e667 | 0;
        this.B = 0xbb67ae85 | 0;
        this.C = 0x3c6ef372 | 0;
        this.D = 0xa54ff53a | 0;
        this.E = 0x510e527f | 0;
        this.F = 0x9b05688c | 0;
        this.G = 0x1f83d9ab | 0;
        this.H = 0x5be0cd19 | 0;
        this._size = 0;
        this._sp = 0; // surrogate pair
        if (!sharedBuffer || sharedOffset >= 8000 /* N.allocTotal */) {
            sharedBuffer = new ArrayBuffer(8000 /* N.allocTotal */);
            sharedOffset = 0;
        }
        this._byte = new Uint8Array(sharedBuffer, sharedOffset, 80 /* N.allocBytes */);
        this._word = new Int32Array(sharedBuffer, sharedOffset, 20 /* N.allocWords */);
        sharedOffset += 80 /* N.allocBytes */;
    }
    update(data) {
        // data: string
        if ("string" === typeof data) {
            return this._utf8(data);
        }
        // data: undefined
        if (data == null) {
            throw new TypeError("Invalid type: " + typeof data);
        }
        const byteOffset = data.byteOffset;
        const length = data.byteLength;
        let blocks = (length / 64 /* N.inputBytes */) | 0;
        let offset = 0;
        // longer than 1 block
        if (blocks && !(byteOffset & 3) && !(this._size % 64 /* N.inputBytes */)) {
            const block = new Int32Array(data.buffer, byteOffset, blocks * 16 /* N.inputWords */);
            while (blocks--) {
                this._int32(block, offset >> 2);
                offset += 64 /* N.inputBytes */;
            }
            this._size += offset;
        }
        // data: TypedArray | DataView
        const BYTES_PER_ELEMENT = data.BYTES_PER_ELEMENT;
        if (BYTES_PER_ELEMENT !== 1 && data.buffer) {
            const rest = new Uint8Array(data.buffer, byteOffset + offset, length - offset);
            return this._uint8(rest);
        }
        // no more bytes
        if (offset === length)
            return this;
        // data: Uint8Array | Int8Array
        return this._uint8(data, offset);
    }
    _uint8(data, offset) {
        const { _byte, _word } = this;
        const length = data.length;
        offset = offset | 0;
        while (offset < length) {
            const start = this._size % 64 /* N.inputBytes */;
            let index = start;
            while (offset < length && index < 64 /* N.inputBytes */) {
                _byte[index++] = data[offset++];
            }
            if (index >= 64 /* N.inputBytes */) {
                this._int32(_word);
            }
            this._size += index - start;
        }
        return this;
    }
    _utf8(text) {
        const { _byte, _word } = this;
        const length = text.length;
        let surrogate = this._sp;
        for (let offset = 0; offset < length;) {
            const start = this._size % 64 /* N.inputBytes */;
            let index = start;
            while (offset < length && index < 64 /* N.inputBytes */) {
                let code = text.charCodeAt(offset++) | 0;
                if (code < 0x80) {
                    // ASCII characters
                    _byte[index++] = code;
                }
                else if (code < 0x800) {
                    // 2 bytes
                    _byte[index++] = 0xC0 | (code >>> 6);
                    _byte[index++] = 0x80 | (code & 0x3F);
                }
                else if (code < 0xD800 || code > 0xDFFF) {
                    // 3 bytes
                    _byte[index++] = 0xE0 | (code >>> 12);
                    _byte[index++] = 0x80 | ((code >>> 6) & 0x3F);
                    _byte[index++] = 0x80 | (code & 0x3F);
                }
                else if (surrogate) {
                    // 4 bytes - surrogate pair
                    code = ((surrogate & 0x3FF) << 10) + (code & 0x3FF) + 0x10000;
                    _byte[index++] = 0xF0 | (code >>> 18);
                    _byte[index++] = 0x80 | ((code >>> 12) & 0x3F);
                    _byte[index++] = 0x80 | ((code >>> 6) & 0x3F);
                    _byte[index++] = 0x80 | (code & 0x3F);
                    surrogate = 0;
                }
                else {
                    surrogate = code;
                }
            }
            if (index >= 64 /* N.inputBytes */) {
                this._int32(_word);
                _word[0] = _word[16 /* N.inputWords */];
            }
            this._size += index - start;
        }
        this._sp = surrogate;
        return this;
    }
    _int32(data, offset) {
        let { A, B, C, D, E, F, G, H } = this;
        let i = 0;
        offset = offset | 0;
        while (i < 16 /* N.inputWords */) {
            W[i++] = swap32(data[offset++]);
        }
        for (i = 16 /* N.inputWords */; i < 64 /* N.workWords */; i++) {
            W[i] = (gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]) | 0;
        }
        for (i = 0; i < 64 /* N.workWords */; i++) {
            const T1 = (H + sigma1(E) + ch(E, F, G) + K[i] + W[i]) | 0;
            const T2 = (sigma0(A) + maj(A, B, C)) | 0;
            H = G;
            G = F;
            F = E;
            E = (D + T1) | 0;
            D = C;
            C = B;
            B = A;
            A = (T1 + T2) | 0;
        }
        this.A = (A + this.A) | 0;
        this.B = (B + this.B) | 0;
        this.C = (C + this.C) | 0;
        this.D = (D + this.D) | 0;
        this.E = (E + this.E) | 0;
        this.F = (F + this.F) | 0;
        this.G = (G + this.G) | 0;
        this.H = (H + this.H) | 0;
    }
    digest(encoding) {
        const { _byte, _word } = this;
        let i = (this._size % 64 /* N.inputBytes */) | 0;
        _byte[i++] = 0x80;
        // pad 0 for current word
        while (i & 3) {
            _byte[i++] = 0;
        }
        i >>= 2;
        if (i > 14 /* N.highIndex */) {
            while (i < 16 /* N.inputWords */) {
                _word[i++] = 0;
            }
            i = 0;
            this._int32(_word);
        }
        // pad 0 for rest words
        while (i < 16 /* N.inputWords */) {
            _word[i++] = 0;
        }
        // input size
        const bits64 = this._size * 8;
        const low32 = (bits64 & 0xffffffff) >>> 0;
        const high32 = (bits64 - low32) / 0x100000000;
        if (high32)
            _word[14 /* N.highIndex */] = swap32(high32);
        if (low32)
            _word[15 /* N.lowIndex */] = swap32(low32);
        this._int32(_word);
        return (encoding === "hex") ? this._hex() : this._bin();
    }
    _hex() {
        const { A, B, C, D, E, F, G, H } = this;
        return hex32(A) + hex32(B) + hex32(C) + hex32(D) + hex32(E) + hex32(F) + hex32(G) + hex32(H);
    }
    _bin() {
        const { A, B, C, D, E, F, G, H, _byte, _word } = this;
        _word[0] = swap32(A);
        _word[1] = swap32(B);
        _word[2] = swap32(C);
        _word[3] = swap32(D);
        _word[4] = swap32(E);
        _word[5] = swap32(F);
        _word[6] = swap32(G);
        _word[7] = swap32(H);
        return _byte.slice(0, 32);
    }
}
const W = new Int32Array(64 /* N.workWords */);
let sharedBuffer;
let sharedOffset = 0;
const hex32 = num => (num + 0x100000000).toString(16).substr(-8);
const swapLE = (c => (((c << 24) & 0xff000000) | ((c << 8) & 0xff0000) | ((c >> 8) & 0xff00) | ((c >> 24) & 0xff)));
const swapBE = (c => c);
const swap32 = isBE() ? swapBE : swapLE;
const ch = (x, y, z) => (z ^ (x & (y ^ z)));
const maj = (x, y, z) => ((x & y) | (z & (x | y)));
const sigma0 = x => ((x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10));
const sigma1 = x => ((x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7));
const gamma0 = x => ((x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3));
const gamma1 = x => ((x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10));
function isBE() {
    const buf = new Uint8Array(new Uint16Array([0xFEFF]).buffer); // BOM
    return (buf[0] === 0xFE);
}

class HistoryItem {
}
class History {
    constructor(editor, maxstep) {
        this._itemid = 1;
        this.items = [];
        this.editor = editor;
        this.maxstep = maxstep;
    }
    GetActivate() {
        return this.activeItem;
    }
    TrySave(txt) {
        let item = new HistoryItem();
        item.id = this._itemid;
        item.text = txt;
        item.width = this.editor.drawCanvas.getWidth();
        item.height = this.editor.drawCanvas.getHeight();
        item.data = this.editor.drawCanvas.getCurrentLayer().getBitmapData().data;
        item.datahash = Bin2Sha256(item.data);
        let s = this.editor.drawCanvas.getCurrentLayer().getSelect();
        if (s != null) {
            item.select = s.Clone();
            if (this.editor.drawCanvas.getCurrentLayer().getBitmapSelect() == null) {
                this.editor.drawCanvas.getCurrentLayer().copyDataToSelect();
                item.dataselect = this.editor.drawCanvas.getCurrentLayer().getBitmapDataSelect().data;
                this.editor.drawCanvas.getCurrentLayer().dropSelectData();
            }
            else {
                item.dataselect = this.editor.drawCanvas.getCurrentLayer().getBitmapDataSelect().data;
            }
            item.dataselecthash = Bin2Sha256(item.dataselect);
        }
        //去重
        if (this.activeItem != null) {
            if (this.activeItem.datahash == item.datahash && this.activeItem.dataselecthash == item.dataselecthash)
                return -1;
        }
        let index = this.items.indexOf(this.activeItem);
        this.items.splice(index + 1);
        this.items.push(item);
        this._itemid++;
        this.activeItem = item;
        if (this.items.length > 20) {
            this.items.splice(0, 1);
        }
        console.log("History ADD:" + item.text + "len=" + this.items.length);
        this.editor.drawCanvas.RePaint();
        return item.id;
    }
    ApplyHistory(item) {
        if (item == this.activeItem)
            return;
        if (this.items.indexOf(item) == -1)
            return;
        if (this.activeItem.datahash == item.datahash && this.activeItem.dataselecthash == item.dataselecthash)
            return;
        this.activeItem = item;
        this.editor.drawCanvas.getCurrentLayer().SetSelectData(this.activeItem.select, this.activeItem.dataselect);
        this.editor.drawCanvas.getCurrentLayer().SetEditData(this.activeItem.data);
        this.editor.drawCanvas.getCurrentLayer().updateBitmap();
        this.editor.drawCanvas.RePaint();
    }
    GoLast() {
        let index = this.items.indexOf(this.activeItem);
        let act = null;
        if (index > 0) {
            act = this.items[index - 1];
        }
        else {
            return;
        }
        console.log("History now:" + this.items.indexOf(act) + " " + act.text);
        this.ApplyHistory(act);
    }
    GoNext() {
        let index = this.items.indexOf(this.activeItem);
        let act = null;
        if (index < this.items.length - 1) {
            act = this.items[index + 1];
        }
        else {
            return;
        }
        console.log("History now:" + this.items.indexOf(act) + " " + act.text);
        this.ApplyHistory(act);
    }
}

var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class Editor {
    constructor() {
        this.drawCanvas = new PixelEdit_DrawCanvas();
        this.timer = 0;
    }
    //looptimer: number = 0;
    update() {
        let time = new Date().valueOf();
        this.timer = (time % 1000) / 1000;
        // this.looptimer += delta;
        // let delta = (time - this.timer) / 1000;
        //console.log("timer=" + this.timer);
        requestAnimationFrame(this.update.bind(this));
        if (this.drawCanvas.IsSelect()) {
            this.drawCanvas.RePaint();
        }
    }
    Init() {
        return __awaiter$1(this, void 0, void 0, function* () {
            this.update();
            DomTool.InitFullScreen();
            //let leftpanel1 = DOM.DomTool.AddPanel();
            //左边栏和其它
            let s1 = DomTool.AddSpliter();
            //中心区和右边栏
            let s2 = new Splitter();
            s1._panel2.AddChild(s2);
            s2.SetSplitPosRight(200);
            //左边栏上下
            let left_area = new Splitter();
            s1._panel1.AddChild(left_area);
            left_area.SetSplitPosTop(24);
            //中心区上下
            let center_area = s2._panel1;
            //center_area._root.style.backgroundColor = "#000";
            //右区上下
            let right_area = new Splitter();
            s2._panel2.AddChild(right_area);
            right_area.SetSplitPosTop(225);
            //左边栏上区
            let group = this.group_func = new Panel();
            this.group_func.Style_Fill();
            left_area._panel1.AddChild(group);
            //工具区分割
            let left_tool_area = new Splitter();
            left_area._panel2.AddChild(left_tool_area);
            left_tool_area.SetSplitPosTop(214);
            //  工具区
            let toolbox = new Group();
            toolbox.SetTitle("工具");
            toolbox._root.style.backgroundColor = "#33c";
            left_tool_area._panel1.AddChild(toolbox);
            let dotsize = new Splitter();
            dotsize.SetSplitPosTop(32);
            toolbox._panel.AddChild(dotsize);
            this.toolbarsize = new Toolbar();
            this.toolbarsize._root.style.backgroundColor = "#33c";
            this.toolbarsize.addButton("media/dot1.png", "1", "1x1像素画笔");
            this.toolbarsize.addButton("media/dot2.png", "2", "2x2像素画笔");
            this.toolbarsize.addButton("media/dot4.png", "4", "4x4像素画笔");
            this.toolbarsize.onPick = (stag) => {
                let dot = parseInt(stag);
                let tag = this.toolbar.getPickTag();
                let tool = DrawToolCenter.GetDrawTool(tag);
                if (tool != undefined) {
                    tool.SetLineWidth(dot);
                }
            };
            dotsize._panel1.AddChild(this.toolbarsize);
            this.toolbar = new Toolbar();
            dotsize._panel2.AddChild(this.toolbar);
            this.toolbar.onPick = (tag) => {
                let dot = parseInt(this.toolbarsize.getPickTag());
                let tool = DrawToolCenter.GetDrawTool(tag);
                if (tool != undefined) {
                    tool.SetLineWidth(dot);
                    tool.OnSet();
                }
            };
            this.toolbar._root.style.backgroundColor = "#aaa";
            // 色板
            let toolbox_color = this.toolbox_color = new Group();
            toolbox_color.SetTitle("色板");
            left_tool_area._panel2.AddChild(toolbox_color);
            let pal = this.palette = new PalettePanel();
            toolbox_color._panel.AddChild(pal);
            toolbox_color.setBackColor(pal.colors[3]);
            toolbox_color.Show();
            let toolbox_template = this.toolbox_model = new Group();
            this.toolbox_model_bar = new Toolbar();
            toolbox_template._panel.AddChild(this.toolbox_model_bar);
            toolbox_template.SetTitle("模板");
            left_tool_area._panel2.AddChild(toolbox_template);
            toolbox_template.Hide();
            let pallastindex = pal.pickindex;
            pal.onPick = (index, indexhide) => {
                if (indexhide == 0)
                    indexhide = 1;
                this.setBackColor(pal.colors[indexhide], false);
                if (index == 0) {
                    this.toolbar.setPickTag("earse");
                    pal.pickindex = pallastindex;
                    pal.Update();
                    if (pal.pickindex == 0)
                        pal.pickindex = 1;
                }
                else {
                    pallastindex = index;
                }
                this.setDrawColor(pal.colors[pal.pickindex], false);
            };
            let img = new Picture();
            img.Style_Fill();
            pal._root.childNodes[0].appendChild(img._root);
            img.setSrc(IO.GetPluginUrl("media/tran.png"));
            //中心绘图区
            let canvas = this.drawCanvas.canvas = new Canvas();
            center_area.AddChild(canvas);
            //右上预览区
            let priview = this.priview = new Preview();
            right_area._panel1.AddChild(priview);
            let right_tool = new Splitter();
            right_area._panel2.AddChild(right_tool);
            right_tool.SetSplitPosTop(260);
            let grouprgb = new Group();
            grouprgb.SetTitle("HSV调色板");
            right_tool._panel1.AddChild(grouprgb);
            let palsplit = new Splitter();
            palsplit.SetSplitPosTop(196);
            grouprgb._panel.AddChild(palsplit);
            let palrgb = new PaletteRGBPanel();
            palsplit._panel1.AddChild(palrgb);
            let label = new Label("当前颜色");
            palsplit._panel2.AddChild(label);
            palrgb.onPick = (c) => {
                label.SetText("" + c.toString());
            };
            {
                let btn = new Button("设置前景", () => {
                    let c = palrgb.getPickColor().ToColor32();
                    this.setDrawColor(c, false);
                });
                palsplit._panel2.AddChild(btn);
                let btn2 = new Button("设置色板", () => {
                    let c = palrgb.getPickColor().ToColor32();
                    this.palette.colors[this.palette.pickindex].R = c.R;
                    this.palette.colors[this.palette.pickindex].G = c.G;
                    this.palette.colors[this.palette.pickindex].B = c.B;
                    this.palette.Update();
                    this.setDrawColor(c, true);
                });
                palsplit._panel2.AddChild(btn2);
            }
            let temps = new Group();
            temps.SetTitle("图层");
            temps._panel.AddChild(new Label(".png 文件不支持图层编辑"));
            right_tool._panel2.AddChild(temps);
            //加载图片和配置
            let pngfile = IO.GetEditBaseName() + ".png";
            //let layerfile = IO.GetEditBaseName() + ".ttimg.json";
            try {
                let file = yield IO.LoadBinaryFile(pngfile);
                let img = yield ImgTool.Bin2ImgAsync(file);
                this.drawCanvas.SetSize(img.width, img.height);
                this.drawCanvas.getCurrentLayer().DrawArea_Init(img);
            }
            catch (e) {
                console.error(e);
                this.drawCanvas.SetSize(32, 32);
                this.drawCanvas.getCurrentLayer().updateBitmap();
            }
            // try {
            //     let layer = await IO.LoadTextFile(layerfile);
            //     let layerjson = JSON.parse(layer);
            // }
            // catch (e) {
            //     console.error(e);
            // }
            this.history = new History(this, 20);
            this.history.TrySave("打开文件" + this.drawCanvas.getWidth() + "x" + this.drawCanvas.getHeight());
            priview.SetImg(this.drawCanvas.GetFinalBitmap());
            //这是data，他不能直接渲染，需要一个backcanvas 转手
            //this._imgedit = await ImgTool.Img2Data(img);
            this.drawCanvas.Init(this);
            PixelEditor_Function.InitFunc(this);
            // this.priview.setBackColor(pal.colors[1]);
            // this.drawCanvas.canvas.setBackColor(pal.colors[1]);
            // this.palette.setBackColor(pal.colors[1]);
            this.setDrawColor(pal.colors[1], false);
            this.setBackColor(pal.colors[3], false);
            DrawToolCenter.Init(this);
        });
    }
    setDrawColor(color, updatepickindex) {
        this.drawCanvas.setDrawColor(color);
        this.toolbox_color.setBackColor(color);
        if (updatepickindex) {
            for (let i = 1; i < this.palette.colors.length; i++) {
                if (this.palette.colors[i].R == color.R &&
                    this.palette.colors[i].G == color.G &&
                    this.palette.colors[i].B == color.B) {
                    this.palette.pickindex = i;
                    break;
                }
            }
            this.palette.Update();
        }
    }
    setBackColor(color, updatepickindex) {
        this.priview.setBackColor(color);
        this.drawCanvas.setBackColor(color);
        this.palette.setBackColor(color);
        if (updatepickindex) {
            for (let i = 1; i < this.palette.colors.length; i++) {
                if (this.palette.colors[i].R == color.R &&
                    this.palette.colors[i].G == color.G &&
                    this.palette.colors[i].B == color.B) {
                    this.palette.pickindexhide = i;
                    break;
                }
            }
        }
    }
    //保存文档
    _save() {
        return __awaiter$1(this, void 0, void 0, function* () {
            let b = yield this.drawCanvas.GetFinalBitmap().getCanvas().convertToBlob({ "type": "image/png" });
            let ab = yield b.arrayBuffer();
            let pngdata = new Uint8Array(ab);
            //进来的时候有可能不是从png来的
            //还可能是ttimg.json
            let pngfile = IO.GetEditBaseName() + ".png";
            //let infofile = IO.GetEditBaseName() + ".ttimg.json";
            IO.SaveBinaryFile(pngfile, pngdata);
            //IO.SaveTextFile(infofile, "not implement yet.");
        });
    }
}
function Tool_PixelEditInit() {
    return __awaiter$1(this, void 0, void 0, function* () {
        let editor = new Editor();
        yield editor.Init();
    });
}

var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
window.onload = () => __awaiter(void 0, void 0, void 0, function* () {
    IO.Init(); //初始化扩展IO系统
    let filename = IO.GetEditFileName();
    console.log("argv:" + filename);
    let ext = TTPathTool.GetExt(filename);
    if (ext == ".png") {
        console.log("这是一个图片");
        Tool_PixelEditInit();
    }
    else {
        DomTool.Init();
        DomTool.AddLabel("不支持的文件:" + filename);
        console.log("不支持的文件");
        return;
    }
});
